{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "缺失值：\n",
    "   - 删除 成列删除/成对删除\n",
    "   - 均值、模型、中值填充\n",
    "   - 预测模型填充\n",
    "   \n",
    "异常值：\n",
    "   - 删除\n",
    "   - 转换 log减轻极值引起的变化\n",
    "   - 填充 人为异常值可填充\n",
    "   - 区别对待 两个模型\n",
    " \n",
    " "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 特征工程"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 数据预处理与特征处理"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-04T06:37:27.156695Z",
     "start_time": "2020-11-04T06:37:27.152673Z"
    }
   },
   "source": [
    "数据采集、数据清洗、数据采样"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## pivot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def api_pivot_count_features(df):\n",
    "    tmp = df.groupby(['file_id','api'])['tid'].count().to_frame('api_tid_count').reset_index()\n",
    "    tmp_pivot = pd.pivot_table(data=tmp,index = 'file_id',columns='api',values='api_tid_count',fill_value=0)\n",
    "    tmp_pivot.columns = [tmp_pivot.columns.names[0] + '_pivot_'+ str(col) for col in tmp_pivot.columns]\n",
    "    tmp_pivot.reset_index(inplace = True)\n",
    "    tmp_pivot = memory_process._memory_process(tmp_pivot)\n",
    "    return tmp_pivot "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 标准化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 标准化\n",
    "# 将特征转换为标准正态分布，并和整体样本分布有关\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "from sklearn.datasets import load_iris\n",
    "iris = load_iris()\n",
    "#标准化，返回值为标准化后的数据\n",
    "StandardScaler().fit_transform(iris.data)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 归一化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 归一化\n",
    "# 归一化是将样本的特征值转换到同一量纲下，把数据映射到[0,1]或[a,b]区间内，仅由变量极值决定\n",
    "from sklearn.preprocessing import Normalizer\n",
    "#归一化，返回值为归一化后的数据\n",
    "Normalizer().fit_transform(iris.data)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "归一化与标准化的使用场景：\n",
    "    \n",
    "    如果对输出结果范围有要求，则用归一化\n",
    "    如果数据较为稳定，不存在极端的最大值或最小值，则用归一化\n",
    "    如果数据存在异常值和较多噪音，则用标准化，这样可以通过中心化简介避免异常值和极端值的影响\n",
    "    SVM\\KNN\\PCA 等模型都必须进行归一化或标准化\n",
    "  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 区间缩放法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 区间缩放法\n",
    "from sklearn.preprocessing import MinMaxScaler\n",
    "#区间缩放，返回值为缩放到[0, 1]区间的数据\n",
    "MinMaxScaler().fit_transform(iris.data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn import preprocessing\n",
    "\n",
    "features_columns = [col for col in train_data.columns if col not in ['target']]\n",
    "min_max_scaler = preprocessing.MinMaxScaler()\n",
    "min_max_scaler = min_max_scaler.fit(train_data[features_columns])\n",
    "\n",
    "train_data_scaler = min_max_scaler.transform(train_data[features_columns])\n",
    "test_data_scaler = min_max_scaler.transform(test_data[features_columns])\n",
    "\n",
    "train_data_scaler = pd.DataFrame(train_data_scaler)\n",
    "train_data_scaler.columns = features_columns\n",
    "\n",
    "test_data_scaler = pd.DataFrame(test_data_scaler)\n",
    "test_data_scaler.columns = features_columns\n",
    "train_data_scaler['target'] = train_data['target']\n",
    "\n",
    "display(train_data_scaler.describe())\n",
    "display(test_data_scaler.describe())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 定量特征二值化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-04T07:05:02.494626Z",
     "start_time": "2020-11-04T07:05:02.468606Z"
    }
   },
   "outputs": [],
   "source": [
    "from sklearn.preprocessing import Binarizer\n",
    "#二值化，阈值设置为3，返回值为二值化后的数据\n",
    "Binarizer(threshold=3).fit_transform(iris.data)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 哑编码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-04T07:10:18.806188Z",
     "start_time": "2020-11-04T07:10:18.792866Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<150x3 sparse matrix of type '<class 'numpy.float64'>'\n",
       "\twith 150 stored elements in Compressed Sparse Row format>"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.preprocessing import OneHotEncoder\n",
    "#哑编码，对IRIS数据集的目标值，返回值为哑编码后的数据\n",
    "OneHotEncoder(categories='auto').fit_transform(iris.target.reshape((-1,1)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 多项式变换"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.preprocessing import PolynomialFeatures\n",
    "#多项式转换\n",
    "#参数degree为度，默认值为2 \n",
    "PolynomialFeatures(degree=2).fit_transform(iris.data)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 特征降维"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 方差选择法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.feature_selection import VarianceThreshold\n",
    "from sklearn.datasets import load_iris\n",
    "iris = load_iris()\n",
    "#方差选择法，返回值为特征选择后的数据\n",
    "#参数threshold为方差的阈值\n",
    "VarianceThreshold(threshold=3).fit_transform(iris.data)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 相关系数法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from sklearn.datasets import load_iris\n",
    "iris = load_iris()\n",
    "from array import array\n",
    "from sklearn.feature_selection import SelectKBest\n",
    "from scipy.stats import pearsonr\n",
    "#选择K个最好的特征，返回选择特征后的数据\n",
    "#第一个参数为计算评估特征是否好的函数，该函数输入特征矩阵和目标向量，输出二元组（评分，P值）的数组，数组第i项为第i个特征的评分和P值。在此定义为计算相关系数\n",
    "#参数k为选择的特征个数\n",
    "SelectKBest(\n",
    "    lambda X, Y: np.array(list(map(lambda x: pearsonr(x, Y), X.T))).T[0],\n",
    "    k=2).fit_transform(iris.data, iris.target)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 卡方检验"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.datasets import load_iris\n",
    "iris = load_iris()\n",
    "from sklearn.feature_selection import SelectKBest\n",
    "from sklearn.feature_selection import chi2\n",
    "\n",
    "#选择K个最好的特征，返回选择特征后的数据\n",
    "SelectKBest(chi2, k=2).fit_transform(iris.data, iris.target)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 互信息法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from sklearn.feature_selection import SelectKBest \n",
    "from minepy import MINE \n",
    " \n",
    "#由于MINE的设计不是函数式的，定义mic方法将其为函数式的，返回一个二元组，二元组的第2项设置成固定的P值0.5 \n",
    "def mic(x, y): \n",
    "    m = MINE() \n",
    "    m.compute_score(x, y) \n",
    "    return (m.mic(), 0.5) \n",
    "\n",
    "#选择K个最好的特征，返回特征选择后的数据 \n",
    "SelectKBest(\n",
    "    lambda X, Y: np.array(list(map(lambda x: mic(x, Y), X.T))).T[0],\n",
    "    k=2).fit_transform(iris.data, iris.target)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 递归特征消除法RFE"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.feature_selection import RFE\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "\n",
    "#递归特征消除法，返回特征选择后的数据\n",
    "#参数estimator为基模型\n",
    "#参数n_features_to_select为选择的特征个数\n",
    "RFE(estimator=LogisticRegression(multi_class='auto',\n",
    "                                 solver='lbfgs',\n",
    "                                 max_iter=500),\n",
    "    n_features_to_select=2).fit_transform(iris.data, iris.target)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 基于惩罚项的特征选择法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.feature_selection import SelectFromModel\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "\n",
    "#带L1惩罚项的逻辑回归作为基模型的特征选择\n",
    "SelectFromModel(\n",
    "    LogisticRegression(penalty='l2', C=0.1, solver='lbfgs',\n",
    "                       multi_class='auto')).fit_transform(\n",
    "                           iris.data, iris.target)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 基于树模型的特征选择法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.feature_selection import SelectFromModel\n",
    "from sklearn.ensemble import GradientBoostingClassifier\n",
    " \n",
    "# GBDT作为基模型的特征选择\n",
    "SelectFromModel(GradientBoostingClassifier()).fit_transform(iris.data,\n",
    "                                                            iris.target)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 主成分分析法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.decomposition import PCA\n",
    " \n",
    "#主成分分析法，返回降维后的数据\n",
    "#参数n_components为主成分数目\n",
    "PCA(n_components=2).fit_transform(iris.data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.decomposition import PCA   #主成分分析法\n",
    "\n",
    "#保持90%的信息\n",
    "pca = PCA(n_components=0.9)\n",
    "new_train_pca_90 = pca.fit_transform(train_data_scaler.iloc[:,0:-1])\n",
    "new_test_pca_90 = pca.transform(test_data_scaler)\n",
    "new_train_pca_90 = pd.DataFrame(new_train_pca_90)\n",
    "new_test_pca_90 = pd.DataFrame(new_test_pca_90)\n",
    "new_train_pca_90['target'] = train_data_scaler['target']\n",
    "new_train_pca_90.describe()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 线性判别分析法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA\n",
    " \n",
    "#线性判别分析法，返回降维后的数据\n",
    "#参数n_components为降维后的维数\n",
    "LDA(n_components=2).fit_transform(iris.data, iris.target)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 赛题特征工程"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 异常值分析"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 绘制各个特征的箱线图"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-04T07:25:42.207475Z",
     "start_time": "2020-11-04T07:25:40.748111Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAABCAAAAI/CAYAAACmvKgRAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8vihELAAAACXBIWXMAAAsTAAALEwEAmpwYAACrrklEQVR4nOz9fXRT5503/H6vLcmSLRtsJw4GBNhPG1IjkyYT+mRKfLrivOCSZghnVqeMnU7mHnuF4tRqzh2mkERdz0yftUQGOuQ+1DS4pHbTaWMdVtvTJJOUB5LYTR8n0/sMmbSJwfe03DcvAZIUMK8CWbJ1nT9gq9rGNhjtS3tv6ftZS0vVxr30y9Z+/e3r+l1CSgkiIiIiIiIiIpU0qwMgIiIiIiIiovzHBAQRERERERERKccEBBEREREREREpxwQEERERERERESnHBAQRERERERERKccEBBEREREREREp57Y6gOtx4403ypqaGqvDICIiIiIiIqIM77777gkpZdVE/+bIBERNTQ327NljdRhERERERERElEEIcWiyf+MQDCIiIiIiIiJSjgkIIiIiIiIiIlKOCQgiIiIiIiIiUo4JCCIiIiIiIiJSjgkIIiIiIiIiIlKOCQgiIiIiIiIiUo4JCCIiIiIiIiJSjgkIIiIiIiIiIlKOCQgiIiIiIiIiUo4JCCIiIiIiIiJSjgkIIiIiIiIiIlKOCQgiIiIiIiIiUo4JCCIiIiIiIiJSjgkIIiIiIiIiIlKOCQgiIiIiIiIiUo4JCCIiIiIiIiJSjgkIIiIiIiIiIlKOCQgiIiIiIiIiUo4JCCIiIiIiIiJSTmkCQghxixDitxmvs0KI/9e4v7lbCHEm42/+D5UxEREREREREVHuuVU2LqX8TwC3AYAQwgXgKIBfTPCn/7eU8kGVsRARERERERGRdXI5BONeAP9TSnkoh99JRERERERERDagtAfEOH8NIDrJv31eCPE7AMcA/L2Ucm/uwsqhu++2OgIiIiIiIiJyil/9yuoITJWTHhBCiCIAKwD8dIJ//g8AC6SUnwXQCeClSdpYLYTYI4TYc/z4cWWxEhEREREREZH5hJRS/ZcI8RCAr0spl13D3x4EsERKeWKyv1myZIncs2ePiRESERERERERUbaEEO9KKZdM9G+5qgHRjEmGXwghqoUQ4vL//t8vx3QyR3ERERERkU1Fo1HU19fD5XKhvr4e0ehko3mJiMgJlNeAEEL4AdwP4GsZy9YAgJSyC8CXAbQLIUYBXATw1zIX3TKIiIiIyLai0SjC4TC6u7vR0NCAgYEBtLW1AQCam5stjo6IiK5HToZgmI1DMIiIiIjyW319PTo7O9HY2Jhe1t/fj1AohMHBQQsjIyKiqUw1BIMJCCIiIiKyHZfLhXg8Do/Hk16WTCbh8/kwNjZmYWRERDQVO9SAICIiIiK6ZnV1dRgYGDAsGxgYQF1dnUURERFRtpiAICIiIiLbCYfDaGtrQ39/P5LJJPr7+9HW1oZwOGx1aEREdJ2UF6EkIiIiIpouvdBkKBTC0NAQ6urqEIlEWICSiMjB2AOCiIiIiIiIiJRjDwgiIiIish1Ow0lElH84CwYRERER2Q6n4SQiciZOw0lEREREjsJpOImInInTcBIRERGRo3AaTiKi/MMEBBERERHZDqfhJCLKPyxCSURERES2w2k4iYjyD2tAEBEREREREZEpWAOCiIiIiIiIiCzFBAQRERER2VI0GkV9fT1cLhfq6+sRjUatDomIiLLAGhBEREREZDvRaBThcBjd3d1oaGjAwMAA2traAIB1IIiIHIo1IIiIiIjIdurr69HZ2YnGxsb0sv7+foRCIQwODloYGRERTWWqGhBMQBARERGR7bhcLsTjcXg8nvSyZDIJn8+HsbExCyMjIqKpsAglERERETlKXV0dBgYGDMsGBgZQV1dnUURERJQtJiCIiIiIyHbC4TDa2trQ39+PZDKJ/v5+tLW1IRwOWx0aERFdJxahJCIiIiLb0QtNhkIhDA0Noa6uDpFIhAUoiYgcjDUgiIiIiIiIiMgUrAFBRERERERERJZiAoKIiIiIiIiIlGMCgoiIiIiIiIiUYwKCiIiIiIiIiJRjAoKIiIiIbCkajaK+vh4ulwv19fWIRqNWh0RERFngNJxEREREZDvRaBThcBjd3d1oaGjAwMAA2traAIBTcRIRORSn4SQiIiIi26mvr0dnZycaGxvTy/r7+xEKhTA4OGhhZERENJWppuFkAoKIiIiIbMflciEej8Pj8aSXJZNJ+Hw+jI2NWRgZERFNZaoEBGtAEBEREZHt1NXVYWBgwLBsYGAAdXV1FkVERETZYgKCiIiIiGwnHA6jra0N/f39SCaT6O/vR1tbG8LhsNWhERHRdWIRSiIiIiKyHb3QZCgUwtDQEOrq6hCJRFiAkojIwVgDgoiIiIiIiIhMwRoQREREROQ40WgU9fX1cLlcqK+vRzQatTokIiLKAodgEBEREZHtRKNRhMNhdHd3o6GhAQMDA2hrawMADsMgInIoDsEgIiIiItupr69HZ2cnGhsb08v6+/sRCoUwODhoYWRERDSVqYZgMAFBRERERLbjcrkQj8fh8XjSy5LJJHw+H8bGxiyMjIiIpsIaEERERETkKHV1dfj2t79tqAHx7W9/G3V1dVaHRkRE14kJCCIiIiKyncbGRmzcuBGtra04d+4cWltbsXHjRsOQDCIichYmIIiIiIjIdvr7+7F+/Xr09PSgrKwMPT09WL9+Pfr7+60OjYiIrhNrQBARERGR7bAGBBGRM7EGBBERERE5Sl1dHQYGBgzLBgYGWAOC8kIoFILP54MQAj6fD6FQyOqQiHKCCQgiIiIisp1wOIxVq1ahtrYWmqahtrYWq1atQjgctjo0oqyEQiF0dXVhw4YNiMVi2LBhA7q6upiEoILABAQRERER2ZoQwuoQiEzz/PPPY+PGjXjiiSdQUlKCJ554Ahs3bsTzzz9vdWhEyrEGBBERERHZTn19PTo7Ow2zXvT39yMUCmFwcNDCyIiyI4RALBZDSUlJetmFCxfg9/vhxHszovFYA4KIiIiIHGVoaAgNDQ2GZQ0NDRgaGrIoIiJzeL1edHV1GZZ1dXXB6/VaFBFR7ritDoCIiIiIaLy6ujp8+9vfxksvvYShoSHU1dVh5cqVLEJJjvfoo49i/fr1AIA1a9agq6sL69evx5o1ayyOjEg99oAgIiIiIttpbGzExo0b0drainPnzqG1tRUbN240DMkgcqLOzk6sWbMGTz/9NPx+P55++mmsWbMGnZ2dVodmmWg0ivr6erhcLtTX1yMajVodEinCGhBEREREZDv19fW4+eabsXPnToyMjMDr9WL58uX4wx/+wBoQRHkkGo0iHA6ju7sbDQ0NGBgYQFtbGyKRCJqbm60Oj64Da0AQERERkaPs27cPv/vd77Bz504kEgns3LkTv/vd77Bv3z6rQyMiE0UiEXR3d6OxsREejweNjY3o7u5GJBKxOjRSgAkIIiIiIrKdoqIiLF26FKFQCD6fD6FQCEuXLkVRUZHVoRHZ2q233gohRPp16623Wh3SlFhwtrAoT0AIIQ4KIT4QQvxWCHHFuAlxyXeFEPuFEO8LIf5MdUxEREREZG8jIyPYsWOHoQbEjh07MDIyYnVoRLZ166234oMPPsCKFStw/PhxrFixAh988IGtkxB1dXUYGBgwLBsYGGDB2TyVqx4QjVLK2yYZB7IcwM2XX6sBbMtRTERERERkU16vF6tWrUJPTw/KysrQ09ODVatWcapCoinoyYeXX34ZN954I15++eV0EsKuwuEw2tra0N/fj2Qyif7+frS1tSEcDlsdGilgh2k4HwLwL/JSNczfCCHKhRCzpZQfWR0YEREREVkjkUjg7bffRk9PT7owXWtrKxKJhNWhEdlad3f3FZ+rqqosiubq9EKToVAoPeUuC1Dmr1wkICSA3UIICeD7Usrt4/59LoAPMz4fubyMCQgiIiKiArVo0SLcfPPNWL58uWEWDL/fb3VoRLbW1taGl19+2fDZ7pqbm5lwKBC5GILRIKX8M1waavF1IcQXrqcRIcRqIcQeIcSe48ePmxshEREREdlKY2MjXn31VWzYsAGxWAwbNmzAq6++isbGRqtDI7KtxYsX45VXXsFDDz2EEydO4KGHHsIrr7yCxYsXWx0aEQBAXBr5kKMvE+IfAZyXUv5zxrLvA/iVlDJ6+fN/Arh7qiEYS5YskXv2XFHPkoiIiIjyRH19PVauXImXXnop3S1b/zw4OGh1eES2pRei1C1evBjvv/++hRFRoRFCvDtJ/Ue1PSCEEH4hRJn+vwEsAzD+jPEKgEcuz4bx5wDOsP4DETlRNBpFfX09XC4X6uvrEY1GrQ6JiMixhoaG8A//8A8YHBzE2NgYBgcH8Q//8A+cmo/ygsprhvfffx9SyvSLyQeyE9U1IGYB+IUQQv+uXinl/yWEWAMAUsouAL8E8ACA/QAuAPg7xTEREZkuGo0iHA6ju7s7XSxNH3PJMY1ERNOnT82XOeSCU/NRPuA1AxWynA7BMAuHYBCR3dTX16Ozs9Nwodzf349QKMSuwkRE1yEajeLxxx+H3+/H4cOHMX/+fMRiMWzZsoU3aeRoHF5E+c6yIRhERIViaGgIDQ0NhmUNDQ3sKkxEZAInPjBTJRQKwefzQQgBn8+HUChkdUg0Tfv27cOLL76Izs5OxONxdHZ24sUXX8S+fftMaZ9DQsnOmIAgIjKB3lU4E7sKExFdv0gkgtWrV8Pv90MIAb/fj9WrVyMSiVgdmmVCoRCee+45VFRUQNM0VFRU4LnnnmMSwmGKiooQCoXQ2NgIj8eDxsZGhEIhFBUVZd22PrwjM7kRDoeZhCDb4BAMIiITTDaeMxKJsKswEdF10DQNCxYsQE9PT/q42traikOHDiGVSlkdniU8Hg9mzJiBn/3sZ+l18uUvfxlnz55FMpm0Ojy6Rpqm4cYbb4Tf78ehQ4ewYMECxGIxnDhxIuttm8M7yA44BIOISLHm5mZEIpF019hQKMTkAxFRFlQ+JXaq0dFR/OQnPzGsk5/85CcYHR3Num1228+duXPnphNGl4v1I5lMYu7cuVm3vW/fPvT29hp6QPT29po2vIMoW0xAEBGZpLm52TBdHJMPRETXL5FIYOvWrejv70cymUR/fz+2bt2KRCJhdWiW+vGPf2xIFPz4xz/Ouk122889n8+Hnp4exONx9PT0wOfzmdJuUVEROjo6DEmqjo6Ogk7ckb1wCAYRERER2Q67kl+ptLQUsVgM7e3teOaZZ/DUU09h27Zt8Pv9OH/+/HW3y5mccsvlcuGFF17Axo0b09v2+vXr8V/+y3/B2NhYVm1rmgav14t4PJ5e5vP5MDIyUrBDlyj3OASDiIiIrsv8+fMhhEi/5s+fb3VIVCDC4fCEXcnD4bDVoVmmoqICJSUl+MEPfoDy8nL84Ac/QElJCSoqKrJqd2hoCEeOHDH0rDhy5AhnclKkrq4OgUDA0GsyEAiYUri6pKQE8Xg8vU1UVFQgHo+jpKQk67aJzMAEBBEREU1o/vz5+PDDD7F06VIcO3YMS5cuxYcffsgkBOVEc3MzvvSlL2H58uUoKirC8uXL8aUvfamgh7cdO3YMXV1dWLhwITRNw8KFC9HV1YVjx45l1e6cOXOwbt06Q7Jn3bp1mDNnjkmRU6ZwOIxVq1ahtrYWmqahtrYWq1atMiW5FovFUFpaip///OdIJBL4+c9/nu45Q2QHTEAQERHRhPTkw9tvv43Zs2fj7bffTichiFSLRqN47bXXsHPnTiQSCezcuROvvfZaQdclUPnkXC+GONlnUkPFen722WcNRbGfffZZ07+D6HoxAUFERJSBleCNfvazn035mUiVSCSC7u5uQzG97u5uRCIRq0OzTDgcRltbm6EwZ1tbW9ZPzo8dO4aNGzcablo3btyYdc8KmlgkEsGOHTtw4MABjI2N4cCBA9ixY4cp27YQAu+9954hSfXee+8xoUS24bY6ACIiIrvQK8F3d3ejoaEBAwMDaGtrA4CC7fb95S9/GW+//bbhM1EuDA0NoaGhwbCsoaGhoOsS6MehUCiULl5oxpTPmT0rdP39/ab0rKArqdy277//fmzbtg0ADIVKly1blnXbRGZgDwgiIqLL+MTVaN68eXjnnXdw11134aOPPsJdd92Fd955B/PmzbM6NCoAdXV1GBgYMCwbGBgo+JtiFVM+q+pZQRNTuW3v2rULy5YtQ1dXF8rLy9HV1YVly5Zh165dWbdNZAZOw0lERHSZy+VCPB6Hx+NJL0smk/D5fFlPjeZUeiFK3bx583D48GELI6JCEY1G8fjjj8Pv9+Pw4cOYP38+YrEYtmzZUrA9klSKRqOIRCLpnhXhcJjrWZFoNIq/+Zu/MZxXXC4XfvzjH3OdU17gNJxERETXgE9cr7Rx40YEg0FomoZgMIiNGzdaHRIVICc+MHMaFT0raGLr16/H2NgYfD4fAKST3OvXr7c4MiL1mIAgIiK6LHNqNJfLZerUaE6k18TInJovHA4XfGFOyo1IJILVq1fD7/dDCAG/34/Vq1cX7JAoyh/6DEMXL16ElBIXL17kDENUMJiAICIimgCfuF66AWxpaTFUxm9paeENIOXEvn370Nvba0iA9fb2Yt++fVaHlpc4A1BuqZxhiL8l2RlnwSAiIrpMnxqtsbExvay/vx+hUKgguyPv27cPsVgMPT096VlBWltbcejQIatDowJQVFSEpUuXGmZ8WLp0KaeGVIAzAOWeqhmG+FuS3bEHBBER0WVDQ0M4cuSI4cnRkSNHCnbav6KiIoRCIcOsIKFQCEVFRVaHRgUgkUigt7cXJ06cQCqVwokTJ9Db24tEImF1aHmHMwDllsoZhvhbkt1xFgwiIpOwgrjzzZs3D6Ojo+jt7U0/OWppaYHb7S7IsbmapqGmpuaKJ2kHDx5EKpWyOjzKcx6PB16vF1VVVelZMI4fP46RkREkk0mrw8srnAEo91TNMMTfkuyAs2AQESnGYn35Qwgx5edCsmjRoglrQCxatMjq0KgAjI6OoqysDD09PYjH4+jp6UFZWRlGR0etDi3vcAag3Dt8+DCklOmXWdMb87cku2MCgojIBOzymB+OHTuGjRs3Gm64N27cWLBjzsPh8IRFAAt1VhDKvb/7u78z7I9/93d/Z3VIeSkcDqOtrQ39/f1IJpPo7+9HW1sb93UHCofDeOCBByCESL8eeOAB/pZkGyxCSURkgqGhITQ0NBiWNTQ0FGztAKeqq6tDIBDA4OBgell/f3/BPjnShxBlFgGMRCIcWkQ5EQgEsGXLFiSTSaRSKfz+97/Hli1bEAgErA7NUjfccAOGh4fTnysrK3Hy5Mms2uS+nj9eeOEFxONxVFRU4NSpU+n3F154gb8n2QJ7QBARmYBdHvMDnwJeqbm5GYODgxgbG8Pg4CAvYClnFi1ahAsXLqTHrY+NjeHChQsFPQRITz4Eg0EcOnQIwWAQw8PDuOGGG7Jum/t6buk9e4QQ6R4+Znj99ddx7733Ys6cOdA0DXPmzMG9996L119/3ZT2ibLFHhBERCYIh8NYtWoV/H4/Dh06hAULFiAWi2HLli1Wh0bTwKeARPbR19cHr9eLVCqFVCoFl8sFj8eDvr4+q0OzzPDwcLoHSG1tbbrX1pEjRyyOjKYjFAqhq6sLGzduxJo1a9DV1YX169cDADo7O7NqW0qJ/fv344c//GG6ePDf/d3fwYkTD1B+Yg8IIiKTFXLRwnzAp4BE9jA6OoqKigrs2rULiUQCu3btQkVFRcEXoRRCGOqy8JzjPM8//zw2btyIJ554AiUlJXjiiSewceNGPP/886a0/9nPftZQk+qzn/2sKe0SmYEJCCIiE0QiEezYsQMHDhzA2NgYDhw4gB07drAIJRFRFlasWGG4kVqxYoXVIVnO5XIZ1onL5bI6JJqmkZERrFmzxrBszZo1GBkZMaX9V155BY899hjOnDmDxx57DK+88oop7RKZgQkIIiITsAgl5atoNIr6+nq4XC7U19dzalnKqe3bt2P27NlwuVyYPXs2tm/fbnVIljt48CCKiooghEBRUREOHjxodUg0TV6vF11dXYZlXV1d8Hq9WbcdDAaxZMkSdHV1oby8HF1dXViyZAmCwWDWbROZgQkIIiITsAgl5aNoNIrHH38csVgMABCLxfD4448zCUE5UVlZCQA4fvw4UqkUjh8/blheiPT6D8lk0vBe6DODOM2jjz6KtWvXGqbKXLt2LR599NGs2w6Hwzh58iTefPNNJBIJvPnmmzh58mRBF1Mme2ECgojIBJw9gfLRunXr4Ha70dPTg3g8jp6eHrjdbqxbt87q0K6KPTecr6SkBCUlJdC0S5ermqallxWy8vJy1NTUQAiBmpoalJeXm9JuU1MTNE2DEAKapqGpqcmUdulKvb2901o+Hc3NzYhEIulZNkKhEIspk60IJ1ZEXbJkidyzZ4/VYRARGUSjUUQikfTsCeFwmCd8cjQhBHbv3o37778/vez111/HsmXLbF1RPRqNIhwOo7u7O10Fvq2tjRfhDqNpGm644QaUlpbi8OHDmD9/Ps6fP4+TJ08ilUpZHZ4lNE1DaWkp4vE4kskkPB4PfD4fzp8/n9U6aWpqwu7du9He3o5nnnkGTz31FLZt24Zly5Zh165dJv4XEHDp2BoMBjE4OJheVl9fj71799r62Ep0rYQQ70opl0z4b07cyJmAICIiUk+fnz4ej6eX6Z/tfP1QX1+Pzs5ONDY2ppf19/cjFAoZLvjJ3nw+HzZs2IAnnngivezZZ5/F008/bdgmC4nH48GMGTPws5/9LJ1c+/KXv4yzZ8+mh2NcD03TsGbNGjz33HPpZY899hi6uroKNtmjkhAChw4dwvz589PLDh8+jAULFtj62Ep0raZKQHAIBhEREU0qHo9j1qxZGBoawqxZs0y98VM1TIJFYfNDIpHA1q1bDUPbtm7dikQiYXVolhkdHcXY2BhaW1vh9XrR2tqKsbGxrKcmlVLi9ttvN+yPt99+O2+GFVq6dKlhfS9dutTqkIhyggkIIiKiDPq4Wf3pfygUsjokSwkhUFxcjEWLFqG4uBhCCFPa1YdJdHZ2Ih6Po7OzE+Fw2JQkBIvC5odFixahpaXFMJa9paUFixYtsjo0SyUSCRw9ehRSShw9etS0hMzatWsN++PatWtNaZeu5Pf7cfToUcRiMfz+979HLBbD0aNH4ff7rQ7NMjz3FhAppeNed9xxhyQiIjJbR0eH1DRNzpo1SwKQs2bNkpqmyY6ODqtDswQA+dWvflV6vV4JQHq9XvnVr35VXrp8yE4wGJR9fX2GZX19fTIYDGbddm9vr6ytrZV9fX0ykUjIvr4+WVtbK3t7e7Num3Knt7dXVlVVyZqaGqlpmqypqZFVVVUF/TtqmiY1TZObN2+WsVhMbt68Ob0sG36/XwKQFRUVUtM0WVFRIQFIv99vUuSUKRgMyrKyMgkg/SorKzPl+OdEHR0d0u12G7Zrt9tdsOfefABgj5zkXp41IIiIiC7zeDxwuVxIpVLpAm+apmFsbCyr8dVOpVfDf+ONN9Ljze+77z6kUqmsu2a7XC7E43F4PJ70smQyCZ/Ph7GxsWxDx6233ooPPvgg/Xnx4sV4//33s26XckefBtbv9+PQoUNYsGABYrEYtmzZUrDFRIUQmDlzJioqKtLr5NSpUzhz5kxW+6SmafD5fLh48WJ6WXFxMeLxOGtAKOByuXDPPffgzTffvHRDJgTuvfde9PX1mXL8cxrWe8k/rAFBRER0DUZHRzEyMpJONiSTSYyMjGQ9vtqphBBIpVJobW3F4cOH0drailQqZcowDJXDJJqamvDBBx+goqICAFBRUYEPPviA0wo6TCQSwY4dO3DgwAGkUikcOHAAO3bsQCQSsTo0S7W3t8Pv90MIAb/fj/b29qzbLCoqwsyZMw3LZs6ciaKioqzbpisVFxfjjTfeSE+hWl5ejjfeeAPFxcWmtK8PZdBfPp/PlHZVGRkZwZo1awzL1qxZg5GREYsiIpWYgCAiIhqnvb0dp0+fNuXC3sn0G5yDBw/i05/+NA4ePJi+8clWOBxGW1ubocBgW1sbwuFw1m3v3r0bXq8XM2fOhKZpmDlzJrxeL3bv3p1125Q7Q0NDOHLkiKFQ35EjRwq6mGggEMALL7xgqNXwwgsvIBAIZNXuyMgIPv74Y8Oyjz/+mDeAisRiMQgh8K1vfQuxWAzf+ta3IIRALBbLum2fz4eRkRFD8eCRkRFbJyG8Xi+6uroMy7q6uuD1ei2KiJSabGyGnV+sAUFERCrg8ljc6upqqWmarK6uTi8rRCrrNEh5aYx/MBiUmqbJYDBo2th+XK7fkVkDQq/rQc4RCATkzJkzZU1NjRRCyJqaGjlz5kwZCASsDs0ymXUx9HViRl0MZNQiGP8i8wGQDzzwgKG+zgMPPGDK+taPf5nsfvzT6y9lnnsLuf5SPsAUNSDYA4KIiGic48ePI5VK4fjx41aHYimVvRQAoLm5GYODgxgbG8Pg4KCp4/o/97nPobGxER6PB42Njfjc5z5nWtuUGxcuXMD58+cRCoUM7xcuXLA6NMs0Nzdjy5YthiEYZtbE0DTN8E7q/PrXv8bOnTuRSCSwc+dO/PrXvzat7V/96ldTfrabpUuXorS0FCdPnkQqlcLJkydRWlrKqUnzFI8uRERE4+hFwAqxGFim5uZmfOlLX8Ly5ctRVFSE5cuX40tf+pIpNzuZ45PHv8zw6quvwuVyQQgBl8uFV1991ZR2KXeGh4fxpS99CU8//TT8fj+efvppfOlLX8Lw8LDVoeUtveAkC0+qJYTA+fPn8dOf/hQXLlzAT3/6U5w/f96049+tt94KTdPShYRvvfVWU9pVJRKJIBQKYeHChdA0DQsXLkQoFCr4ei/5igkIIiIimlA0GsVrr71meEr32muvIRqNZt12ZnfMiT5nw+/3A7jyZkpfTs7x3//7fzdsf//9v/93q0OyVDQaRTgcNtSACIfDpuyTwKWZgIQQhtlpSA2fz4dt27ahvLwc27ZtM61GgxACyWQSXq8Xv/nNb+D1epFMJk1Lbqiwb98+vPjii4bt+sUXX8S+ffusDo0UYAKCiIiIJhSJRNDS0oJQKASfz4dQKISWlhbbP5UaGRlBaWkpampqIIRATU0NSktLWVDPYdxu9xXT3yaTSbjdblPaj0ajhgKXZt3EqxSJRHD48GHcc889KCoqwj333IPDhw+btk8mk0lIKQty2uFcWrRoEWbPnm1YNnv2bCxatMiU9jVNQzwex5//+Z8jHo/bfkhNUVERQqGQYdhcKBQybRYWJ+7r+czeWyMREVGOFRUVpZ/+eTyegp6GzqlPpUZHR/Hwww/jo48+gpQSH330ER5++OGCnU7VqcbGxuByudDa2gqfz4fW1la4XC5Thkap7kmgyt69e6/47x8bG8PevXstioiuh6ZpOHDggGHZgQMHTEkUSCnR2tqankHC6/WitbXVlN5lqiQSCWzdutVQb2jr1q1IJBJZtx2NRvH4448jFotBSolYLIbHH3/c9vt6PmMCgoiIKEMikUg//Usmk6ZcADmV6qdSqrjdbvz0pz81dN3/6U9/atqTc8qNRYsWYfXq1emhM36/H6tXrzblKbFTe/fogsEgDh06hGAwaHUodB0++OADAEBpaanhXV+ere7ubpSXl0MIgfLycnR3d5vSriqLFi2acH80Y19ft25d+jyuD0NJJBJYt25d1m3T9WECgojIJOziR1fjtG0kkUjgn/7pn1BbWwtN01BbW4t/+qd/sn1SZsaMGTh9+jTee+89JJNJvPfeezh9+jRmzJhhdWg0DXoPhd///vdIpVL4/e9/n+6pkK19+/aht7fX0AOit7fX9r17gEtPzzs7OzF79mx0dnbavns9TeyLX/wizp07Byklzp07hy9+8YumtCuEgJQSd955J/74xz/izjvvhJTS1jUgwuEwtm/fjlgsBgCIxWLYvn27Kfv6kSNH0v87sxdI5nLKLR6xKOecdgFOdC2c2p2XcseJ28jcuXPTvUH0i9dkMom5c+daGdZVnT59Gl/72tcMsyd87Wtfw+nTp60OjabhnXfewdmzZw09ks6ePYt33nkn67aLioqwdOlSwxPXpUuX2r53DwC4XC5D3C6Xy+qQ6DpUV1dP+fl6SSlx++2341//9V9RVVWFf/3Xf8Xtt99u6yEYABCPx3H06FGkUikcPXoU8XjctLYnOo+RhTKrTjvldccdd0hypt7eXllVVSVramqkpmmypqZGVlVVyd7eXqtDI8pKMBiUfX19hmV9fX0yGAxaFBFdDwASgPR4PIb3S6fL7DhxGwkEArK6ulr29fXJRCIh+/r6ZHV1tQwEAqZ+jxnrN5MT1zVdSdM0KYSQs2bNMrxrmpZ12wCk2+2WmzdvlrFYTG7evFm63W7Tt0Wz6ccjTdPSLzOOUXobFRUVhne7rw+n0tdte3u7PH36tGxvbzdtfQOQzc3NMhgMSk3TZDAYlM3Nzbb+LQOBgJw9e7bhXDN79mxTzjUApBDCsK8LIWy9PvIBgD1yknt5IW2eDZvIkiVL5J49e6wOg67DvHnzMDY2hhdffBENDQ0YGBjAww8/DJfLhQ8//NDq8Iium8vlQjweN0xdlkwm4fP5TCmYRrmhPx3ZvHkz1qxZg66uLqxduxaAsevm9XDiNuJyufC1r30NPT09GBkZSRcz+/73v29qzHqXYbPoRcf8fj8OHTqEBQsWIBaLYcuWLWhubjbte0gtIQT8fj+qqqpw+PBhzJ8/H8ePH08Xk8uGz+fDl7/8Zfz2t7/F0NAQ6urqcNttt+FnP/uZqU9ezVZaWprupp7J7/fj/Pnz193uVN3znXivYHe33nrrhPUeFi9ejPfffz+rtvVtpKKiAqdPn0Z5eTlOnTqV9TaikhACu3fvxv33359e9vrrr2PZsmVZb39CiCuK1+qfuW2rI4R4V0q5ZKJ/4xAMyqkjR47gRz/6kaGg2Y9+9COOwyLHq6urw7e//W3D8KJvf/vbqKurszo0ug5r166F3+9PJx/MUFdXh4GBAcOygYEBW28jc+bMwS9+8QtDMcdf/OIXmDNnjtWhXZXenVdKaXp3Xsqdixcv4uDBg0ilUjh48CAuXrxoSruJRAJvv/22YUjU22+/bfv6JvrMBte6/FpVVlamb9SASzdoQghUVlZm1S5NbPwUnFdbPh36tnDq1ClIKXHq1CnD8kI0NjaWrpWiaZptk/6FggkIomvE2hU0lcbGRjzzzDM4ceIEUqkUTpw4gWeeeQaNjY1WhzYlbtdGqi7ugUtFth566CEUFRVBCIGioiI89NBDphTZUuns2bNoampCUVERmpqacPbsWatDuqp169bB5XJh7ty50DQNc+fOhcvlYtVzB0qlUumn80IIpFIpU9pdtGgRbrvtNixfvhxFRUVYvnw5brvtNlOq7qs0PDx8RdFJTdMwPDycVbtbt26FlDJ9Y6Y/Hc62XR3PNUavv/467r33XgSDQWiahmAwiHvvvRevv/561m0PDw9DCIHq6mpomobq6moIIUz7LVUIBAJ45JFHDNNwPvLIIwgEAqZ9x0033QRN03DTTTeZ1iZdp8nGZtj5xRoQzoXL49smetlZb2+vrK2tNYxNq62tZe0KSgsEArK4uNhQO6C4uNj0sfJm4nZ9pd7eXkPdB/23NGOddHR0SCGEdLlcEoB0uVxSCCE7OjpMiFyNXB2zVbQ3Ue0Ku59ryEjl9tfR0TFhDQg7749Sqq0d0NvbK4PBoAQgg8GgaecCnmuuBEBWVlYaaqJVVlaaVgPCadfamTXihBCm1ogDIEtKSgzXZyUlJbZeH/kAU9SAsDyZcD0vJiCcK/MAA8AxRShZ0IyuBoCcOXOm4WJi5syZtj7BcbuemKqLcLfbLSsrKw0X4ZWVldLtdpvSvgr6RWt1dbXUNC19E++EBMTnP/956fV6JQDp9Xrl5z//eVvvj3QllTdSwWBQhsNhQ6E+/bOd6dtz5nFE387N/A4zOXVdq6QnoTNvivXktBlt620ODAyYWkxZJf3cq28jZp179X0mc12bvc/QlSxLQACYB6AfwD4AewE8PsHf3A3gDIDfXn79H1drlwkIZ1N1ca+SpmkykUgYliUSCVMqcVN+cOIJjtv11FTcFP/yl780LPvlL39p620EOaoerqI9sKK/4+m/WWavIbN+R6ce//T/fn3GDv3dzgkI/Yl2ZtJEf9JdqPTfbOnSpfLYsWNy6dKlps6C4bQeECrp56zxL7O2P1WJE6ebKgGhugbEKIC1UspFAP4cwNeFEBMNrvu/pZS3XX79n4pjIos1NzdjcHAQADA4OOiIiuROLB5HuTcyMmIYPzsyMmJxRFPjdp17+rFvss929JnPfAZPP/00/H4/nn76aXzmM5+xOqRrlllvg5xLr/tgVv0HwPnHv0vX986YoaKoqAh33XUXQqEQfD4fQqEQ7rrrroLfL0tKSvDOO+9gzpw5eOedd1BSUmJq+6WlpRBCoLS01NR2nUbfRzJryWQuz0Y0GkU4HDYUsw2HwwVf4+SqJstMqHgBeBnA/eOW3Q3g1em0wx4Q+QEOysRy/CJdDfCnudkz3+28nXO7nprZv11lZaXUNM3Qm0DTNFlZWWnq95gJOXqSpqI9n89n6JHk8/lsvT/SlVRufyrrvajk9/sn7N3j9/tN+w4V++NE9TYKeX/UtzkVvbT0djKHoNn9ekRKtUMwFixYYFgfCxYsMG0oF4eyTgx2qAEBoAbAYQAzxi2/G8BJAL8DsBNA8GptMQGRH+x+IByPXaxoKrm6UTObE7drp94U9/b2yhkzZhhuimfMmGHrde7UdQ1AFhUVGdZ1UVGR7fdHMlK5/S1evFgCkKWlpYb3xYsXmxC5Opqmyfvuuy/drVwIIe+77z5Th46YvZ94vV551113GW4A9c+FSuW27cTrEZXnR/2h0Pjkvxnrw6lDuXJhqgSEkDnouiWEKAXwFoCIlPL/O+7fZgBISSnPCyEeALBFSnnzBG2sBrAaAObPn3/HoUOHlMdNagkhHNF1kOha6F36JsLtXB2VxxEVbUejUUQiEQwNDaGurg7hcNjWw9BytV2bva41TYOUEhUVFTh16lT63cxpHEk9ldufEAIrVqzAyy+/nF720EMP4ZVXXrH1MXuydRIMBk0b0mX2/iiEgNvtxsaNG7FmzRp0dXVh/fr1GB0dtfW6BtQds1Vu2x6PB6Ojo1csd7vdSCaTWbWtyg033IBTp05h1qxZ+OMf/4ibbroJn3zyCSoqKnDy5Mms2taH4c2ZMweHDh3CggULcOzYMSQSCVOOI5Ox+7atmhDiXSnlkon+TXUNCAghPAB+DuDF8ckHAJBSnpVSnr/8v38JwCOEuHGCv9supVwipVxSVVWlOmxyICHEpC8zcA5romunen90Kr0GztjYmGNq4ABATU0NNE1DTU2N1aFcE/3C79y5c4b3Qr8gJKMzZ85A0zQIIaBpGs6cOWN1SFfV29uL2tpa9PX1AQD6+vpQW1uLcDhscWST83q9WLVqFXp6elBWVoaenh6sWrUKXq/X6tCm5NTx/TNmzJjW8uloamoy7DNNTU1ZtwkAw8PDKCkpgc/ng5QSPp8PJSUlGB4eNqX9RCKBM2fOQAiBM2fOIJFImNLuZPtjb2+vKe3nrcm6RpjxAiAA/AuA//cUf1MNpHti/O+4NExDTNUuh2DkByjsCmZ22yrnJ6b8AAd2ecwVJ+3ruWrbKfRtOLNOiIrtWkV7zc3NhuFFzc3N/E0VUHns09tRUVtHZduqqZ5NzOx1IISYsN6Q3WfBUDm+34n7zbJlyyQA2d7eLk+fPi3b29slALls2TJTYlY1bE719ZkTZ/fLBVg4DWfD5R/4ffxpms0HAKwBsOby33Tg0hSdvwPwGwBLr9YuExD5wUk3DoFAQFZXVxtOntXV1TIQCJj6PXQJ6xLkFyft67lq2ylytV2raG+iY7ZZ39PR0WEYz97R0WFKu06n4ndUfZMWDAbloUOH0jcQTtrvVcVqdrvBYFCGw2HDeV3/bGeapsn29nbDvt7e3m7K+H7V2/btt99uWN+333571m0LIWR7e7thWXt7uymJJJUJwcyC23pCXUXBbScdO3LBsgSEqhcTEPnBSTcOAOTu3bsNy3bv3s2DjQKZvU00TXNMbxMmICbnpH09V207hVMTEIFAQM6cOdNwHJk5c6YpSeOOjo4JK/ozCeG8BMRNN91kaFP/7BROSUA49bxeWVkphRBy1qxZEoCcNWuWFEKYMnNRLpJr1dXVUtO0dPI127YByO3btxsSG9u3bzc15rKyMqlpmiwrK3NcLwUnHTtyYaoEhPIaEET5YuvWrfD5fBBCwOfzYevWrVaHlJfWrVuXLpJ06fgFJJNJrFu3zsqwiLLmxLoYk8Vm55gBYNOmTSgqKgLwp+NIUVERNm3alHXbzz//PO688048/fTT8Pv9ePrpp3HnnXfi+eefz7ptyq0VK1YYLopXrFhhdUh56/Tp0zh48CBSqRQOHjyI06dPWx3SVek1A9atW4dYLIZ169alawg4wccff4xUKoWPP/7YtDbXrl1rqImxdu1a09r2eDyIx+NIpVKIx+PweDymta3XXwLgqPpL+Sons2CYbcmSJXLPnj1Wh0FZclL1+tLSUsRisSuW+/1+nD9/3rTvoUu/ncfjMVRq1j/b+Xil35BVV1enKzjrJ307x50LTtrX86FtMwkhsGrVKgwODqarwNfX12PHjh2mxu+kGUf04mtVVVX45JNPMGvWLBw/fhypVMoRv6lKKmZPmEy235MP1etVHUdUXUONn5XG7tdQQgg8+OCDeP311zEyMgKv14v7778fr776qq23P71tTdOQSqXS79m2rf+O7e3teOaZZ/DUU09h27ZtpvyOQgj4/X5UVVXh8OHDmD9/Po4fP45YLGb7c00u2nYiS2fBIMoHEyUfplpO2Rk/TZRdp42aiH4jcvz4catDITLFu+++i3379iGVSmHfvn149913rQ7Jci6XC8XFxdA0DcXFxXC5XFaHRNPU0dExreV0/WKxGLxeL2bOnAlN0zBz5kx4vV5HXEO9/fbb2LlzJxKJBHbu3Im3337b6pCumZ50MGvq4YsXL6K+vh7btm1DeXk5tm3bhvr6ely8eNGU9mOxmKGXjBO2D7o+TEAQXSMhhGEqOrt3QSZrjI2NGd6JnG7//v3p6fK8Xi/2799vcURXF41G8fjjj6efnsViMTz++OOmTZ+XTCbT3bDPnDnjqCQpXdLZ2YmOjg7Dtt3R0YHOzk6LI8tPepJOf0LshKSdPjXre++9h2Qyiffeey89dasTuFwuaJpm2rqeM2cOTpw4gb6+PiQSCfT19eHEiROYM2dO1m13dHRACJGO1eVyQQjBhGCecsYeRBNy2lhip7vppptw6NAhpFIpHDp0CDfddJPVIeW1iooKCCFQUVFhdSjXpLe3F8XFxYZlxcXFtp8LmseR/KBqbnZdPB43vNvdunXr0vO869tzIpEwrZaMx+PB+fPnkUqlcP78eVPHKlPu6GPZAaTHtJMaFy5cwMGDByGlxMGDB3HhwgXT2o5Go6ivr4fL5UJ9fb1piUYpJfx+P5588knDu1O62Y+NjSGVSpn6QOTs2bNoampCUVERmpqacPbsWVPa7ezsxNe//nW43W4AgNvtxte//nXuk3mKCQgH04smZf5vpxwUneiTTz4xrO9PPvnE4ojylxACM2fONLzbXXNzM7q7uxEMBgEAwWAQ3d3dti90xOOI8zU1NWH37t0oLy8HAJSXl2P37t2mJyGc5MiRI0gkEjh69ChSqRSOHj2KRCKBI0eOmNJ+Mpk0dG9mDwgia6js7bRo0SJ84xvfwMKFC6FpGhYuXIhvfOMbWLRokQmRO8+RI0cQj8dRWVkJAKisrEQ8HjftuMqEYOFgAoImpCqbTHQtpJQ4c+YMUqkUzpw545gbYlZZJivs3r0bZWVl+PnPf45EIoGf//znKCsrw+7du037jvb2dpw+fRrt7e2mtanaxYsXDUkCs8Yp65w23IrndcpH69atw/DwsKF3xfDwsCm9ncLhMHp7ew2zPvT29iIcDpsQufMIIdDY2Igbb7wRmqbhxhtvRGNjoyMeEpG9cBaMPGB21VU9m+z3+3Ho0CEsWLAAsVgMW7ZsMfWGykmVaPOhWrZT5MO6dmIlZCftj2z7yrZeeeUV/MVf/EV62b/+67+mpxjMtm0AV1SvB8zdH1Uds82uAp/Z9kRUtZ1tu9FoFOFwGN3d3WhoaMDAwADa2toQiURsfV7P1fnAicdswDmzYDhxxofMtidiZtw6s+M2e53oQ/y+853vYM2aNejq6sI3v/lN02cAcsq5N5dtOxFnwaBpyRw7qzNz7KxTfeELX0AwGISmaQgGg/jCF75gdUh5iZXJiabv1VdfnfJztvSkg/7uFJlV982mX+Sb+fRv/DAos4ZERSIRtLS0IBQKwefzIRQKoaWlBZFIJOu2iezgO9/5DmKxGL7zne+Y1uZk+6OZN5mpVCr9MpvZs2DoPSB6enpQVlaGnp4e9oCg68IEBF3hyJEj8Pl86OnpwcjICHp6euDz+Uwb4+VUv/71r7F3716kUins3bsXv/71r60OyTKTFS404yTEyuRE0+P3+7F9+3Y89thjOHPmDB577DFs374dfr/ftO8oLS01vDuBpmmGQpFmVq53uVxYsGABNE3DggULbF/Rf9++fRN2Jd+3b5/VoRFlze/34/bbb4fH48Htt99u6rFPNb2ArRMK2Uop8dZbb6G1tRXnzp1Da2sr3nrrLT71p2ljAoImtHbtWjQ2NsLj8aCxsRFr1661OiRLLVu2bFrL7UJVkkD1UwEWIiK6ds8//zx8Pp9hbnafz4fnn3/etO84f/684d0JUqkUSktLoWkaSktLTX3CKKVEKBTCuXPnEAqFbH8BXlRUhI6ODsN5vaOjA0VFRVaHRpS1kZERtLa2wufzobW1FSMjI1aHdM30ArZOKGQbDAbx4IMP4umnn4bf78fTTz+NBx98MF18m+haMQFBE3r22WfR39+PZDKJ/v5+PPvss1aHZKldu3Zh2bJlhi63y5Ytw65duyyObGqc4YAo/zU3N6Onp8cwRKynp8e0sf1/9md/Zjj2/dmf/Zkp7ebC2bNnkUqlTJsqTpdKpbB27Vr4/X6sXbtWSfdpMyUSCXR2dhrO652dnVcMtyRyotHRURw8eBCpVAoHDx7E6Oio1SFdVUdHB4QQhmknhRC2Hm4aDofxu9/9Djt37kQikcDOnTvxu9/9rmCLctL1YxHKPOCkYkHjv8eJhWCcWGTGqevDiesacGbcTv0d2bZa8+bNw+joKHp7e9PFC1taWuB2u/Hhhx+a9j0qzmN6wbSxsTG4XK50obRsv6e0tBSxWOyKwpx+v9/UHiJmrpP6+nqsXLkSL730EoaGhlBXV5f+rM/cYwYnFRMd/z1O2B/HYxFKIBQKYevWrVcsN3vopop1HQqF8Pzzz2NkZARerxePPvqoKTE7sVDu+O9w4rnXqccRVViEkqalt7cXVVVVqKmpAQDU1NSgqqoKvb291gZGREQ5tWnTJoyNjaG1tRVerxetra0YGxvDpk2brA7tqqSUhqkyzbow1Ie8ZBbmNHvIi9mcPp2g3++HpmmOGttPueHkulFOHG7KnrVkBiYg6ArNzc3YsmVL+kTv9/tNn4KTiIjsr6WlBcePH8fBgwchpcTBgwdx/PhxtLS0WB3alHp7e1FbW4u+vj4AQF9fH2pra01JpGcOeQFg+pAXFZqbmxGJRAyzYJg9BadK586dQyqVwrlz56wOhWzIiTfyRIWMQzDygFO7E7Ht3HHq+nDiugacGbdTf0e2nTtOWx/RaBSRSAR79+5FMBhEOBw2/YbbaetENbNj9ng8hp4swKUZSIQQphbtc+K6BjgEY6LvceL+6MT17aT1kQ9tOxGHYBAREVFBaW5uTtc3GBwcdMzTfvqTNWvWQEqJ6upqAEB1dTWklFizZo3FkRER0fVyWx0AEREREdF4eld6vb7GqVOn8Nhjj7GLvcO43e4JZ6bQZ4AgosLCIRh5wKndidh27jh1fThxXQPOjNupvyPbzh2nrg+2nTtOXR9OXNeAc4ZgAJeG02QmIdxut6nDaADnbiMcgsG289FUQzCYeiQiIiIiImX0ZANv0oiICQgiKigTPRmw+8VQLubdJmfjNkJX48RjHxER5R8WoSSigpF5AV5ZWTnhcjsaP9c2592m8Tg3O01lsmOc3Y99RESUf9gDgogKTuaNGS/AiYiIiIhygz0giKigZPZ8mOgzERERERGpwQQEERWU4eHhKT8TEeUrTdMM70RERLnGMxARFRwhBG644QYOvyCigpJKpQzvREREucYEBBEVjMzaD5k9H1isj4iIiIhIPSYgiKhghEIhuN1ubN68GbFYDJs3b4bb7UYoFLI6NCIiIiKivMcEBBEVjOeffx4bN27EE088gZKSEjzxxBPYuHEjnn/+eatDIyIiIiLKe0xAEFHBGBkZwZo1awzL1qxZg5GREYsiIiIiIiIqHExAEFHB8Hq96OrqMizr6uqC1+u1KCIiotxxu92Gd1InFArB5/NBCAGfz8ehfpQz8+bNm9ZyolxjAoKICsajjz6KtWvXQgiRfq1duxaPPvqo1aERESk3OjpqeCc1QqEQurq6sGHDBsRiMWzYsAFdXV1MQlBOHD58+Ipkw7x583D48GGLIiIyEk6s/r5kyRK5Z88eq8OwDSGEsir+bDu3bavi1PVhdttTTbtp9vc4ZZ2obpdt57ZtJ8bMttW3zWNfbtv2+XzYsGEDnnjiifSyZ599Fk8//TTi8bhp38PjCNu2qm0nxuzktp1ICPGulHLJRP/GHhCkXGVlpeGJs/4CMOHyyspKiyOmfBcMBqFpGoLBoNWhEBE50kTndoDndYD1hoiIpsIEBCl36tQpSCmv+XXq1CmrQ6Y8F4vFDO9ERDQ90zm3F9p5nfWGiIgmxwQEERUkdpMzH3s7EU3fdPabbPeZvr4+JBIJ9PX1mRE6TWJkZGTCekPsAUFExAQEUd5ht9irO3jwIKSUOHjwoNWh5BWVvZ2Y3KB8lcueBPfccw82bNiAe+65x6ToaSJSSnR0dKR7PHi9XnR0dDDxTZQHeD2SPRahzAN2L6gy3Tas+E67tG2G6cQ33f+WysrKa74ArqiowPDw8DW3PREWocxd23bf1516HHH6PsO21betcj/I/P9N5nrjz0XcZrfBtq1tl23nT9tOjNmstq24HnEiFqHMI3y6TVZS9aQul9nkWbNmGbohz5o167rbovygcvvjOHkjPjmyht/vtzoEyoLKYTq8riSiXHNbHQBNj34xey2meuJBZCfT2a6B7LbtTz75hN2PySCX21+h47q2xvPPP4/W1lbDFJA+nw89PT0WRkXXSuW1H68riSjX2AOCiApGb28vqqqqUFNTAwCoqalBVVUVent7rQ2MiEih5uZm9PT0pKceDgaD6OnpQXNzs8WR5RZ74OQH/o75gz1wChMTEJTmxIMAT0I0Hc3NzdiyZUu6O7Lf78eWLVuu+yI8l9XrzeTEfZ2IstPc3IzBwUEAwODgYMElHwBOC54v+DvmlsprBg5TLEwsQukwQtijaJsT45ju3+e6eJxZ7LL+7BKHXdow4/vMaseJv2MhtG2X7Vpl207d11W27dRtxIlxO3X7c+LxzE5tqLr2AwqjeDC3v+zaUPn72pmYoggla0AQTYLjIomoUE12ET7Rsc5OCVgiomywTg2RehyCQWSxibqw8YRGRFZit1giyhaH+xk5ddimE3GItr2xBwSRxTIz7YXaTYuIpo+9FHJnqm7ZXN8ETG8bKZTtgz1Jjbg+coc9WeyNCQhSTv7DDOAfZ07v7+m6TWd9c10TORcvZnOHF7N0NdwfiYiuDYtQOs00buQv/f2Za/5TuxRWc2LbhVBgEIC67W+67U6n7UnYfl0rbMcu+wHbtmccKtsuhCKA0/17Rx6zpxmLXYoAOvV3ZNv2jENl23a6ZnDiccQuv+P1/H2+mKoIJRMQDmOXHcSJcahs204nikJYf068KSmEbcQu25Od2nbihZvKtlXGwRvX/GjbLnFM+++5r+eubYUPLezy31gI1wwq27bVvg5k/dDMiZiAyCNOfFJil4ORyrZ5orBvHHZpoyC2kQK4KFTZtl3iUNm2XeJwatt2iUNl23aJQ2XbdonDqW3bJQ6VbU83DpVTxxfC+rNL2/lkqgQEa0BQmvj22entfP+oNh6iQubEgmbTOYYAPI4QAazbQ0TZYw0SchImIIiIbIgXE0SFgcl/IiIqJMoTEEKILwLYAsAF4AdSyn8a9+9eAP8C4A4AJwGsklIeVB0XEVG2+OSSrMTtj8herjUZXFFRoTgSKjROPR84NW7KjtIaEEIIF4DfA7gfwBEA/w6gWUq5L+NvHgNwq5RyjRDirwH8P6WUq6ZqlzUgrB+j5MQ4pv33CgtKTcbW4/sVts0aELltm/Ve7Nm2XeJQ2bZd4nBq29cTx7Wa9lAuHkds2YZT158T41DZtl3icGrbdonjev4+X0xVA0J1AuLzAP5RStl0+fNTACClfCbjb3Zd/pt/E0K4AXwMoEpOERgTENbvIE6MQ2XbZh1cCvVChReF+dG2XeJwatt2iQMAby5t2rZdjn3Tbccu65pTPue2bR5HnB+HU9u2SxzX8/f5YqoEhOohGHMBfJjx+QiAOyf7GynlqBDiDIAbAJxQHBsRFYJJLoCm7PZXgNMlEWViXQLKRyyUm1tOPI5MZ0hA+u+JaFocU4RSCLEawGoAmD9/vsXREJFT8IKTroYXnLnDdU1kLxyDb8RrBiL1OATDYezSRcgucajsTskhGLlr2y5xqGzbLnGobNsucTi1bbvEobJtu8Qx7b9XfK65VmZMuVvIQzA43C8/2rZLHNP+e4W1xezy32iXtu0Sx/X8fb6YagiG6gSEG5eKUN4L4CguFaFskVLuzfibrwNYLP9UhPIvpZRfmapdJiCs30GcGIfKtpmAyI84VLZtl7Gz043FievaqW3bJQ6VbdslDju1rbINle0qW382ebBwPX9vhzacuh84MQ6VbdslDqe2bZc4rufv88VUCQilQzDkpZoOHQB24dI0nD1Syr1CiP8TwB4p5SsAugH8WAixH8AwgL9WGRORHVRWVuLUqVMT/tv4p2FmPPEi53Hi2FkiK3F4R37Ily7wLpcLqVQKwKUYNU3D2NiYxVEREVlPaQ8IVdgDwvoMnRPjUNm2XeJwatvT6YIMTC8pY6f/RjvEobJtW3VdBWzxVNQu688ubdslDju1rbKNTLfeeis++OCD9OfFixfj/fffv+72uI1MLjP5kOl6kxB2+W+0S9u8ZmDbV+XQa4Z8YlkPCHKeaz2oV1RUKI6ECslkB+ZCPWjTlfLlqSiRFcYnHwDggw8+wK233ppVEoImNlHyYarlND28Zsg9p90f8JrB3piAoLSJdlQezImIiJxtfPLhasuJiHS8PyCzMQHhQE7LQgLT6y5np7idSuU24sTtj8hK3GeIqFDx+Jc7XNfkFExAOIwTs5DsKpdbKrcRJ25/RFbi8Y+IChWvGXKH55rc4oPV7DABQTQFZpPzA08UucN1nVvs7URERJQ7TPZkjwkIoknwAJMfVP+OTr1JUxE395ncYm8nIiLzMZGeW069jqLrxwQEkQWmM18956q3L6fecPPmkogKlRNvLnnNkDtOPa87Fa9HChMTEEQWmM70QJwaiIjIek68cSUjx95c/uOZCRfbPm66Ap/2EzEBQURERDQlx964OhSTPZSPeBwhuoQJCCIiIiKyBd6kERHlNyYgyPH4pISIiIiIiMj+mIAgR+OTEqLCoTLZyERmfuDvSDR9rEtARLnEBAQREdmeymQjE5n5gb8j0fRxFgIiyjXN6gCIiIiIiIiIKP+xBwQRkU2xWywRERHR9HFInn0xAUFkEd5c0lTYnZyIyLk0TUMqlZr0MxGpw2soe+MQDCILSCknfE30b8PDwxZHS0RERNORSqXSDxAqKiqYfCAiuow9IIiIiIiITOJ2u+FyuXD+/HkAwPnz5+H1ejE2NmZxZERE1mMPCCIiIiIik4yNjaGoqMiwrKioiAkIIiIwAUFEREQ5JIS45hdr4JATzZ0794pkw9jYGObOnWtRRERE9sEEBBEVjMwbm4k+E5Fa06l/wxo45FQXLlzAxYsXUVlZCSEEKisrcfHiRVy4cMHq0KhANDU1QdMu3eZpmoampiaLIyL6EyYgiKhgSCnR0dEBr9cLAPB6vejo6GBFZCIiMs3w8DDKyspQXFwMACguLkZZWRkTapQTTU1N2L17tyG5u3v3biYhyDaYgCCighEKhbB161aMjIwAAEZGRrB161aEQiGLIyMionzyrW99CwcOHEAqlcKBAwfwrW99y+qQqEDs3r17WsuJck048cnfkiVL5J49e6wOwzZUzmnLtvOjbSfGrKLtqYZamP09Tlknqttl27lt24kxs231bas49k0nPjP+W5yyrvX2qqur0dvbi4aGBgwMDKClpQUff/yxI841TlrXbHvi9iZj5jHFKesjH9p2IiHEu1LKJRP9G6fhJKKCk3mCYP0HIqLrc63Hz0IrJhoIBHD+/Hm0trbi0KFDWLBgAeLxOAKBgNWhERFZjkMwiKjg+Hw+CCHg8/msDoWIyJFYTHRymzZtgsfjAfCnJI3H48GmTZusDCtvlZaWGopLl5aWWhwREU2FCQgiKjj6haH+TkREZJbm5mZs2bIFfr8fAOD3+7FlyxY0NzdbHFn+KS0tRSwWMyyLxWJMQigSCoXSD298Ph9raNF1YQKCJjR//nxDNnn+/PkWR0RknvPnzxveiYjo+nB644k1NzdjcHAQY2NjGBwcZPJBkfHJh6stp+sXCoXQ1dWFDRs2AAA2bNiArq4uJiFo2liEMg+YXfRk/vz5+PDDD69YPm/ePBw+fNi073FqIRgntu20mJuamvD6669DSgkhBO6//37s2rUr63ZZhDL37bLt3LbtxJjZtrG9iZhRwHEyTrkOdNLvmCtOOY6o3P54Xp+4vclk8z0+ny89i5iZ7Y7npHWdq7adaKoilOwBQVeYKPkw1XIiM6mev1rTtCk/ExFZZaL6CbygJafr6OiA2+3G5s2bEYvFsHnzZrjdbnR0dFgdGk3DZMkHouliD4g84JTM6UTf48QspBPbdlLMuXhSsnTpUvzsZz/Dl7/8ZbzzzjumtD3+e5yyvlW3y7Zz27YTY2bb6rEHhHVtq+SU44jP58OXv/xl/Pa3v8XQ0BDq6upw22234Wc/+xni8XhWbfOadeL2JpPN93BdW9e2E7EHBBHRZS6XC//+7/+OOXPm4N///d/hcrmsDokoaxyDT0R2NTIygl27diEWi0FKiVgshl27dvGJuoP95Cc/sToEcjAmIIiooKRSKSSTSQBAMplEKpWyOCKi7LHrPhHZ2fiizywC7VxCCHz1q19lkpuuGxMQRFRQpJSGKaR4k0b5ILPXg9m9H6LRKOrr6wEA9fX1iEajprVNRIUhHo9j+fLlOHXqFJYvX5710AuyzptvvolEIoE333zT6lDIoVgDIg84ZezYRN/jxHFYTmzbSTHnogaEpmlIpVLpdzPaHv89Tlnfqttl2+rbVrnPRKNR/M3f/A3GxsbSy1wuF3784x+bOq2gU9Z1Lts2E2tAWNe2Sk45HwghcPPNN2P//v3p2a0+/elP4w9/+ANnwVDQtuoaEEII7Ny5E8uXLzcUDDeLk9Z1rtp2ItaAIDJBKBQyPDnnvMfO5PV600mHVCoFr9drcURE5ujr60MikUBfX59pbba0tBiSDwAwNjaGlpYW076DiPLf/v37MWvWLGiahlmzZmH//v1Wh0TXSUqJL37xi7zZpuvGBISD8YY4d0KhEL73ve9hdHQUADA6Oorvfe97XOcOdMcddxjGyN9xxx1Wh0SUta9+9avpc0IoFMJXv/pVq0MiGyouLoamaSguLrY6FCogmqZBSonjx48jlUrh+PHjkFJyGmyHqaysnNZyoslwz3co3hDn1rZt2yClTD8JHBsbg5QS27Ztszgymq533nkHDz30EE6cOIGHHnooPQ0nkZP95Cc/QWdnJ+LxODo7O02vUF5WVgZN01BWVmZqu5RbFy9eRCqVwsWLF60OhQqI3uvwxhtvhBACN954o2E5OcPw8DAAIBgM4tChQwgGg4blRNeKCQiH4g1xbo3vgny15dM1f/58w9i6+fPnm9IuGQWDQQgh8Morr6CqqgqvvPIKhBDpkyiRaioLOt5zzz0oKirCPffcY1qbupKSEkgpUVJSYnrblDsVFRUQQqCiosLqUK4Zi6Dmh+bmZkMCwswaMio1NTWle2pomoampiaLI7JWVVUV9u/fjwULFmD//v2oqqqyOiRyICYgHEr1DTHlzvz58/Hhhx8aln344Ye2T0KUlpYakialpaUWR3R1Bw8ehJQSNTU12L9/P2pqaiClxMGDB60OjQpANBrFww8/jL179wIA9u7di4cfftgRN1TDw8OQUvJJ12VOuynRj9WnTp2ClBKnTp0yLLeraDSK1tZWwz7T2trqiH2GjPr7+w29tPr7+60O6aqampqwe/duQ6HF3bt3m7a/OzG5dvr0aUMdrdOnT1sbEDkSZ8FwqFzMFKCi7fHf45RKtE5f32avj9LSUsRisSuW+/3+rOf2Vr2u58yZg4qKCgwNDaGurg6nTp3CsWPHTFk/45NJ8+bNw+HDh7NuN5PZv+UNN9xguKmsrKzEyZMnTWsfcNa+rrJtl8s1YZdjTdOySh7r+4zL5cLY2Fj6HXDG8Un/Hqf8jvpNyXjLli3Drl27TPseM82bNw+ffPIJkslkepnH48GsWbOuSIDbiX6uGT9zkRnnmkxOrV7vlFkw5s2bhz/+8Y9IJBLpZUVFRbjpppuy3v6cen0WjUaxZs0aXLx4EclkEh6PB8XFxejq6sq6d4jqWTDKysoQi8Xg9/tx7ty5rNvVRaNRRCIR7N27F8FgEOFw2PSeMk461zgdZ8EgKlA33HCDoZfCDTfcYEq7EyUfplpuJ+vWrZvy8/VyYk+W8ckH4NKTbrO2EzKabLyzGeOghRB4/fXXkUgk8Prrr9v+ybaTTZR8mGq5HVy4cAGjo6NwuVwALiWrRkdHceHCBYsjm5p+Tsl84pq5nJxh0aJFhuQDACQSCSxatMiiiK5da2uroXB1a2urKe22tLTg7Nmz6aRgMpnE2bNnHTHD0Llz55BKpdLJBzPoUz5n9nb6m7/5G0f0CqHpYwKCyCba29tx+vRptLe3m9KefnNZVFQE4NLTBt5cAmvXrjV0A127dq0p7U72FMfOTxcn607PbvbO097ebpgFw6zjCKue5wd9CM34ulFO2dczEyfkPG+88QaEEJg1axYAYNasWRBC4I033rA4MpquGTNmTPn5ej3yyCMTTvn8yCOPmNK+Sk4cSmM1JiCIbOKFF15ARUUFXnjhBVPaGx4ehqZpmDNnDgBgzpw50DTNMRecKuhd3TOL9Y2NjXEqMMopj8djeDfD9u3bDYm17du3m9LuyMgIgEvFCzVNSxcv1JcXsswaEE6xefNmxGIxbN682epQpkW/yTHrZkfntFoeTpVKpbBhwwZ8/PHHkFLi448/xoYNGxwxC0ZPTw9cLheEEHC5XOjp6bE6JEudPXt2ys/XS5/V71qX20U0GsVXv/pVQ8+Nr371q0xCXIVzzppEee7ixYuQUpo6PVoqlUoXWDx48KAjTvYqqewCT3StMrvcmsHv92N0dBRNTU3w+XxoamrC6Ogo/H5/1m3HYjEsXboUFy5cQCqVwoULF7B06VJHdIFXXSg3szCdE5SWluL222+Hx+PB7bff7ojCwTqz9xngT7U8ysvLAQDl5eWmFhgko9/+9reor6+Hy+VCfX09fvvb31od0lXNmzcPwJVDgPTlRC0tLVdcQ6ZSKUcMpbESExCUc+yqRFbr6+tDIpFAX1+f1aEQZe38+fPw+/1IJpNIpVJIJpOmFunbv38/du7ciUQigZ07d2L//v2mtKvSRIVyY7GYqTfdTktAxONxQ++veDxudUjXTN+WzSw8qdfs0GcE0d/tXMsDuJRM01+Zn+1MCIEdO3bgC1/4AoaHh/GFL3wBO3bssH3cH330Edxut2GZ2+3GRx99ZNp3OLEnlYpefFRYnLO1U16IRqMIh8Po7OwEAHR2diIcDjMJQTnV2toKr9drWjEpIqs9//zzCAaD0DQNwWAQzz//vGltnzp1Ck1NTSgqKkJTU1P6Rs3OnFwoVwUhBEZHR1FWVgZN01BWVobR0VHb3wCqNmPGDNTU1EAIgZqaGtOHeKiQWRAx82VnFRUVEEJg+/btKC8vx/bt2yGESA/psqvR0VE88cQThmPrE088YeqwgPG9K5xARY8kKixMQFBOtbS04MCBA7jnnnsAAPfccw8OHDhQ0F2VvF4vFi5caHiasXDhQni9Xosjy19Hjx6FlBJHjx61OhSirGUmdvUaEGYmdpPJpKF4IS86nUc/v2QOpclcbneqnhKfO3cOBw8ehJQSBw8eNLWqv0p6T1J9OIPdH+KcPn0a9957r+Fm+95778Xp06etDewafO9730snLmOxGL73ve9ZHJH1NE3DG2+84aheG6rpQ/6cNLTNStxyKKf0pwyZXeD1pw+FKpFIIJlM4s0330QikcCbb76JZDJ5xZRVZB5m73NDn5UBQHp2BjJfJBJBd3c3Ghsb4fF40NjYiO7ubkQiEVPad7lchhsHJ81EYPbsQk6VSqWwevXqdHdyt9uN1atXO+Kpq9frNcyCYWZyXkpp6E5u954EgPqEowpz5szBnj17sGDBAmiahgULFmDPnj3pItl2JYRALBbD4cOHkUqlcPjwYcRisYK+ZgWAkpISVFRUoKSkxOpQbOP8+fOQUpo6TCyfMQFBOVVUVIS77rrLMF3cXXfdlZ4qshAtWrQILS0thnXS0tLiiPmxKXecVq1dCIGtW7emZ0sYGRnB1q1bC/7CTYWhoSE0NDQYljU0NGBoaMiU9sfGxgw3gOOnSrOzbdu2oby8HNu2bbM6FEt5vV7EYjF8+tOfhqZp+PSnP41YLOaInnaPP/44Fi5cCE3TsHDhQjz++OOmtu+0hHQkEpnwmsGshKMKFy5cwLlz5xAKhQzvek8cu5osIeWERJVK58+fxx133MGbbbp+k40ls/PrjjvukIUOwKQvu7ftdrvl5s2bZSwWk5s3b5Zut9uUtsd/j9ntqVonvb29sra2Vvb19clEIiH7+vpkbW2t7O3ttW3MTm67paVFBoNBqWmaDAaDsqWlxfZxL1u2bMJ2ly1bZtuY9XaEEIZ3u+/rKttWtb6DwaDs6+szLOvr65PBYDCrdqX8U8yzZs2SQgg5a9YsR/yOKrdtv98vAUhN0wzvfr/fhMjV0I8h7e3t8vTp07K9vd2UY4hqbrdb+v1+WVNTIzVNkzU1NdLv90u325112/r2MP53VHlMMYMQQpaVlUmPxyMBSI/HI8vKyqQQwrTvULE/rlixQnq9XglAer1euWLFCtufewHIxsZGwzVDY2OjqXG7XC7Du53XiX4uz1wf+rndrjFP9D1mt5eLuJ0IwB45Wc2ayf4h2xeA7wD4HwDeB/ALAOWT/N1BAB8A+O1UgWa+mIBw7g2g1+uVd911l+EkpH82k6oDjMfjkZqmpU/8Zn1Pb2+v4YCebfJBSuduI6rbnjFjhuFidsaMGY6IW9XFhOqYq6urpaZpsrq62hEXEyrbVrW+VSUxM2POTBo74XdUuW273W5ZWloqa2pqpBBC1tTUyNLSUlNuilUJBoNy5cqVhnPvypUrTUlSqaQnTioqKgzvZiRO9O1BdXLNbJmJksyXpmmmfYeK/bG4uNiQNCkuLjb1XKMikaRvH5nHVn07MStuXjOob3v895jdXi7idiJYlIBYBsB9+X9vBLBxkr87CODG6bTNBIRzDwL6ySHzhK+fLMzEA4yztxFVbVdWVhouNPXtsLKy0tZx82Ji6u9RxUnHERVJTCkvxaz3UtNfhd5rDYD84Q9/aFjfP/zhD219PtA0TSYSCcOyRCJh6k2rCsFgUNbW1hp+v9raWlN79zitB0Tmunj66aeVHFvNXgf6U/LxPXDM6LWh/7dnJjfMWh8qk41OPP8GAoEJ2wwEAraNeaLvMbu9XMTtRJgiAaGsBoSUcreUUp+n5jcAAqq+i5zD7XajuLgYxcXFAJD+3+PnWSZSoaSkBC6XC5988gkA4JNPPoHL5Sr4QkqZhenMVlRUBCFEQdd5yYXm5mYMDg5ibGwMg4ODaG5uNqVdffrGzPojTpm+US+AOtnn6+X1ejE8PGxY38PDw7aup1BXV4dvf/vbhpkTvv3tb6Ours7q0Ka0b98+HD58GJs3b0YsFsPmzZtx+PBh7Nu3z7TvcOI0iAAQDAbxT//0TwgGg1aHclVSSvj9fuzcuRMVFRXYuXMn/H6//iDSFCpqeaxZswYXLlxAPB6HEALxeBwXLlzAmjVrTPsOJzly5AiEEKiuroamaaiuroYQAkeOHLE6NHKYXBWhbAWwc5J/kwB2CyHeFUKszlE8ZJHR0VGUlpaip6cHIyMj6OnpQWlpqWlzKrPqPk3lyJEjGB0dRUVFBTRNQ0VFBUZHRwv+5Knvf2bOba5LJBKQUpo6q4sQIv2a6DOZz4k3afF4HCtWrMDx48exYsUKxONxU9p99NFHsX79ejz77LO4cOECnn32Waxfvx6PPvqoKe2r0NjYiI0bN6K1tRXnzp1Da2srNm7ciMbGRqtDu6q7774bPT09KCsrQ09PD+6++26rQ7Kcz+czzIJhVnJNpa9//evw+/0QQsDv9+PrX/+61SFdVWdnJx577DGcOnUKqVQKp06dwmOPPYbOzk6rQ7NMaWkpent7EY/H0dvby2kn6fpM1jXiWl4A3gAwOMHroYy/CeNSDQgxSRtzL7/fBOB3AL4wyd+tBrAHwJ758+er6y/iEHBg1y297SeffNLQdfXJJ580pe2Ojo4JY+7o6DAlblXrRBUnbyMq216xYoVhmVMKYalo24kx55LZsTpxneQqZhXtuVwuQ7dsvcibGTo6Ogz1FMw4z6ikciiDSoC6wtX6enDqEAyVtSvMXgeZxUT1oQxmFxNVdYxatmyZoZiyWYVbnXj+BS7VYcmsiaHXZbFrzBN9j9ntOe28niuwogbEpe/FfwHwbwBKrvHv/xHA31/t71gDwpkHLikvjR+bPXu24eA1e/Zs248fc+IBRvX6EEIYLsCdUAkZgFywYIFh+1uwYIEj4lZ1MeG0mHOJFyrGm53M90K/KFRVc0MV/b99/Bh8O297Ul6qHXDfffcZ1vV9991nWu2A+fPnG85j8+fPt/06ycVxxOx1kFlMVAihpJioivWRGbemaY6JW2/H7OSavp9kJnb1/cesmFWfH512rnEyWFEDQgjxRQDrAKyQUk440a8Qwi+EKNP/Ny4VrhxUFRNZb9OmTTh//jyamppQVFSEpqYmnD9/Hps2bbI6NJqmS8cWpMeG65/tTAiB0tJSLF++HEVFRVi+fDlKS0vZdV+hzGESTsDhHRP7y7/8S5w+fRp/+Zd/aXUo18Tlck1r+XREo1GEw2FDF/hwOIxoNJp12yqtWLECzz33HGbOnInnnnsOK1assDqkq5JS4le/+pVh6MivfvUr0843hw8fNgxBO3z4sCntqjTZf7udz8FHjx7FypUrceHCBUgpceHCBaxcuRJHjx417Tsy64SYZffu3SgrK8PPf/5zxONx/PznP0dZWRl2795t2nc46Rzp9/sxMjKSvm4qLS3FyMgI/H6/1aGR00yWmcj2BWA/gA9xaXrN3wLourx8DoBfXv7f/xsuDbv4HYC9AMLX0jZ7QDj3yWVvb6+sqqoyTINYVVVl6nRx46frMnOdOKmrplO3EZVtL168WAKXhmEcP348Pfxi8eLFto5bVdt6G06ah9zJnLhOchWz2e2prLofDAZlX1+fYVlfX5+thzMAkDfeeKOhC/yNN95o621PykvresmSJYYu8EuWLDF1FozS0lLDu93XSS6YvQ5UzsKi+tz7wAMPGHrJPPDAA7Y/R6pqOxAIGK4T9OuGQu7F7MTzeq7AolkwPi2lnCelvO3ya83l5ceklA9c/t//S0r52cuvoJQyoioesodIJIIdO3bgwIEDGBsbw4EDB7Bjxw5EIub99KdOnTK8m8mJhdjoT1KpFKqqqvDKK68Y3gv995wxY4bh3UwejwdCCHg8HtPbdqr29nacPn0a7e3tVoeSt6SUePDBB9HT04Py8nL09PTgwQcfNOUp8dDQEBoaGgzLGhoaMDQ0lHXbKp0/fx7An5606p/trLGxEf/xH/+Bm266CQBw00034T/+4z9MLZ554cIFw3shi0ajqK+vBwDU19eb1qunrq4OX/nKV+Dz+SCEgM/nw1e+8hXbz8ICAL/85S9RXl4OIQTKy8vxy1/+0uqQLHP06FGkUinMmjULQgjMmjULqVTK1J4sKkx2E2zG+YCuT65mwSACcOnC7ciRI4apwI4cOWL7CzfKD3v37sWpU6cMXTVPnTqFvXv3Zt32ZCcyJ5zgVCbtkskkpJSmTo3mdNu2bUN5eTm2bdtmdSh57Qtf+ALi8TiklIjH4/jCF75gSrt1dXUYGBgwLBsYGLD1zZTf70c8Hsfy5csxPDyM5cuXIx6P277r9EsvvZSe9hRAerrTl156yZT2b7/99vQxWkqJ22+/3ZR2nShzaBEAU4cWzZ07Fy+99BJKSkqgaRpKSkrw0ksvYe7cuVm3nQt33nkn/vjHP+LOO++0OhTLrVmzBh9//DFSqRQ+/vhjx0xJeuuttxqGVN56661Wh1TYpsoK2fXFIRjO7U4UCARkeXm5YQhGeXl5QXffUiUX60PlcBcVcQshZHt7u2FZe3u7Kd2yVVK1TrjP5Jb+3+/EoVyqYza7vcrKSulyuQyzJ7hcLllZWZl12729vbK2ttZQzLa2ttbWhSg1TZOVlZWG/bCystKULvAqAZcKn2aua70QarbcbresrKw0tF1ZWWnKzAxOFAwGlR2z3W63LC0tNQwBKi0ttf0sGADSs67oL7NnYXHS+RdQO5RL1fWCPvx2/HAruw+/dTpYNQuGqhcTEM48cEmp9qLQqetEFaeuD32s7/iXWVXPVc2CoZLKiwnV20h1dbXUNE1WV1fbfp/RqZrhYPzYWf3lcrlMaV8FAPKGG24wjMG/4YYbTP8dzW6vt7dXlpWVGaq1l5WVmfZbOm0WDL/fL4Era2L4/X6rQ5sSALlp0ybDsk2bNpmyvXR0dEhN0wzTWWqaZvspVVXRNE22t7cb6h20t7ebVqfhwQcfNLT94IMPmnau8Xg8hgdb+n5vRtv69KF62/q+ZEbbqs+/mdfaZrTtdrsnnAXD7km7zG1ET5yYuY047f4gV5iAyEP6xq1nYjMztGa1reqg+OSTTxou3J588klHxO20A0zmzU3mu93Xh36jM/6JqxkJCK/XKx9++GHD9vfwww9Lr9ebddsqOTkBoaKXjEoqn247+Tii+ndUsQ6cliRQCbj01C9zu9afAtoZADlz5kzDDeDMmTNNi3vZsmWG5JoZ0ys6leoHREIIQ9tmT91t9s22lJeSMkIIQyJdCGFq8UxN0+Qbb7xhau8yVecaJycynT59qBMxAZGHnHqzDUDu3r3bsGz37t2mxq2iq7ATDzBOTUAA6p6UdHR0TBiz3Z94qU5AjJ+b3azfUe+aqb+cUnVf1QwHTj6OVFRUSE3THJWAoD8BILdv325IyGzfvt32610fJjK+l0KhDqVRSeWQFP2YoQ+f0d+dcD0ihDBcR5mVOFHd21PF9TBwaRaxzOszfTYxO9P/21UkqZx4Xs+VqRIQLEJJORUIBPDII4+gv78fyWQS/f39eOSRRxAIBEz7Ds5UYTQ2NmZ4dwJVxeN++MMfTmt5oSgqKjK8m8Hv9+PEiROGGR9OnDhh+6J3uZjhYMWKFTh+/DhWrFhhWpuqnTlzBqlUCmfOnLE6FLoOQghs2bIF+/fvRyqVwv79+7Fly5b0jBh2VVJSgrKyMhQXF0MIgeLiYpSVlaGkpCTrtiORCLq7u9HY2AiPx4PGxkZ0d3ebOiuXk4yOjuKf//mfEQqF4PP5EAqF8M///M8YHR01pX0hBE6cOAEAOHHihGnbnqZNfCsz2fLp8Hq9WLp0KdxuNwDA7XZj6dKl8Hq9WbctpcSCBQvQ19eHRCKBvr4+LFiw4NLTYZOouB7u6OgwXJ91dHSY1rZqb731Fi5cuIC33nrL6lAKHhMQNCmPxwNN00ydPm/Tpk0YGxtDa2srvF4vWltbMTY2hk2bNpnSfklJCWpqaqBpGmpqaky5SMmkrwsnTCk42cnd7heclZWVWLduHdxuN4QQcLvdWLduHSorK7NuOxaLoaamxpCFrampQSwWMyFy5/rjH/8IKSX++Mc/mtbmyMgI/H4/du7cicrKSuzcuRN+vx8jIyOmfYcKqmc48Hq9hmlgzbiQVe3mm29OXxRLKXHzzTdbHBFNVyAQwN69e3HHHXfg2LFjuOOOO7B3715Tk/8qHDt2DC0tLfjoo4+QSqXw0UcfoaWlBceOHcu6bc7KZeT1enHq1CkMDg5ibGwMg4ODOHXqlCnHKCEEFi1aZLiRX7RokSnXI5PdXJtx051IJPDOO+8YpuF85513kEgksm7b6/WioaHBkPBpaGgwZX1rmnbFuhVCZJ2UCQQC+Ku/+ivU1tbC5XKhtrYWf/VXf2X744gu89xL1mICgiaVTCaRSqVMnT6vubkZW7Zsgd/vhxACfr8fW7ZsQXNzsynt6/MRZ76bSV8XTphScLIsupnZ9dLSUsO7GZYsWQLgyp4b+vJsPf7444YLzscff9yUdlWbOXPmlJ+vh57kyby51JM+2RodHUVnZ2e6x4Pf70dnZ6dpT9NUCYfDaGtrM/TSamtrQzgcNqX9kZERLF26FMeOHcPSpUttn5CprKzEH/7wB7hcLgCAy+XCH/7wB1MSgpQ7f/zjH7Fw4UL827/9G+bMmYN/+7d/w8KFC01NOqowZ84c/OIXv8DOnTuRSCSwc+dO/OIXv8CcOXNMafsb3/gGYrEYpJSIxWL4xje+YUrbTvToo49i/fr1ePbZZ3HhwgU8++yzWL9+PR599NGs25ZSYu/evWhtbcXp06fR2tqKvXv3mnY9MmPGDNTU1EAIgZqaGsyYMcOUdl0uF0pKSlBcXAwAKC4uRklJSfp4mI1HH30UO3bsQGtrK86dO4fW1lbs2LHDlPVdV1eHhx56KJ3M8Hq9eOihh7JOpK9cuRJnz57Fhx9+iFQqhQ8//BBnz57FypUrs45ZJf33qq6uhqZpqK6uNiwnC0w2NsPOL9aAcG4NCJUqKyvTY0RxeYyhEMLUGTacOH2eqm1k/PhFs8ZFZq7bzJdZRZ/cbrdhjKtZU2qppK+D0tJSKYRIF4/LNm69CnxmgS2zqsB7vV65efNmw7LNmzfbvuCnlOqKFzrx2Lps2bIJj31mF+uz8zrIBwDk6tWrDWO3V69ebfv1HggE5OzZsw3H7NmzZ5sydbd+zTC+wKAZ1wxO1dHRYdhGzKqP5PV65V133WVoW/+cLQDy05/+tOGY/elPf9q0a53q6mrD9qfP6GQGVetbP26PLxaZ7XE7EAjIkpISQzHHkpISU/ZHlTJryej3B2bVknHieT1XwCKU+QeArKqqMhy4qqqqCjoBEQgEZHl5uWGanfLyclMOjCqLBamix7hixQp5/PjxdKEgu28jejsqpm904u8o5Z/WiYoCXqqqwKtMbjiVE4+tuZo5xs7rIB84cQpYKdVPDVlUVGRYH/pnMpcQQlZVVRlmM6mqqjK14OLSpUvlsWPH5NKlS029HlFZdFFlwkfFcVu//shMyOjXI3amaZq87777DNc69913n6mzmTjpvJ4rUyUgOATDwY4fP46mpibDuxNEo1FDF/hoNGpKu8eOHcN3v/tdw/CO7373u6aMFb20H137cjtRMeZtsjGKZo1n93g88Pl8AACfz2dazQ0n/456ITZN09KF2LIVjUbx5ptvpv/7pZR48803Tdknly5ditLSUpw8eRKpVAonT55EaWkpli5dmnXblDsjIyO47777DMvuu+8+2w8dISN9KJs+Llx/t3tx4jlz5uCll14yDMF46aWXTBsmkUwmMWvWLAghMGvWLEcMr3SiuXPnptetfr5JJpOYO3du1m3rQwnfeecdzJkzB++8845pQwkrKyvx6quvory8HABQXl6OV1991ZQhaKFQCM8995yh7eeeew6hUCjrtkdGRrB9+3ZDPY/t27ebctxeu3atoXDr2rVrs25TtTlz5mDv3r148803kUgk8Oabb2Lv3r2mHEcWL14M4Mpjq76cJsYEhMM5raBKNBpFOBxGZ2cn4vE4Ojs7EQ6HTbnhqaurQyAQMBxwA4GAqcXjMgtcOqF4nCqTncTMuilJJpM4fPgwUqkUDh8+bOpFYTAYNGRhg8GgaW2r9LnPfc5QT+Fzn/tc1m0+8sgjV9yAjI2N4ZFHHsm67UgkgpdeegmJRAJSSiQSCbz00ksFW2E+U2YNCLtzu93o6OhIF2qNxWLo6Ogw5eKeci8z2egU42M1M3YpJdatW4fz589j3bp1jlovTqOvW/0Gzax1PTo6mk4gAUgnlMyqNySlTBdwzKyZlK2uri4UFxcbHiwUFxejq6sr67a9Xu8V7XR1dZly3RqJRAxFKJ1yTld1HHn//fexePFiw7F18eLFeP/9901pP29N1jXCzi8OwchNF3gVbQeDQdnX12dY1tfXJ4PBYNZtq5zTG5e7x2WOe9O7zdmV/pvp9QLMqhugt+31eg3dKc1aH6q37fnz5xu2kfnz59v6d5RSSr/fL4Erx3P6/f6s2tXXa0VFheHdjPWhaZpMJBKGZYlEwpQuj06l/2aZ27T+2a5UbXvj2Xkd5AN9e9u8ebOMxWJy8+bNjugmrGma/Jd/+RdDV/J/+Zd/Ma3rdElJieE8VlJSYvt14kSZQzD0IbJmDcFQXV/iySefNGx/Tz75pGnXI6qGM6gaAllZWTnhtZnd66aoPI7Q5MAaEPknFwmIzJttp9yUqC4e58QilCpiBiA/85nPGE74n/nMZ0zd/lTFffPNNxu2kZtvvtnWv6OUl7br4uJiw35eXFyc9fat/3aZF0BmJZKCwaAMh8OGda1/LlSZCR9N00xN+KgCQNbU1Bi2Pf2z2d9D6ui/nYo6MiqpfGihJ9Iyb4rtnhB0KpVFiYUQ0uVyGZJrLpfLtPoSKhMQmeeAzM/Z6u3tlTNmzDBcx8+YMSPrawZ9/6ioqJBCiHS8ZiekzabyOEKTYwIiD+kHq/FPpez+BNqpBwGV60QV4FJl6MyiO2ZWhlaZJFDV22TevHkSuLJY1bx587JuWzUVyTVA3awgHR0d0u12Gy4K3W43i1A68Dgy0exCTkhAqEpIO5ETtz0p1fZszJw5K/Pd7k9znUhP8GT+jnriJ1sqC+XmYna1YDAoDx06JIPBoO2vtQHIz3/+84aHT5///OcL+jhCk2MCIg/pN02ZBwH95sqMtlVdqPT29k7YDc/uBwEnXrzpVc8zL64Ac6qeq1wfqp9K6fuJ/nJC8kGVzN4UQghDL4tssQfElZx4HMl8cp55HLF7AoIXnEZO3PZ0qmYK6O3tlWVlZYZkd1lZWcFuIyqpPB+oHN6hcqpW/eFN5vanP8zJlqohBwDkjBkzDMOWZsyYUdDHEZrcVAkIFqF0sA8//BAlJSUQQqCkpAQffvih1SFNi16IyEkqKioghEBFRYXVoVzVvffeC+DSbClSyvQsKfpyu6qsrMSFCxcQj8chhEA8HseFCxdMqToNAIcPHzYcBA8fPmxKu06kF7W8ePEipJS4ePGiYXk2hoaGcMsttxiW3XLLLRgaGsq6bcq9EydOQEqJEydOWB3KNYlEIuju7jZUa+/u7nZMwTS6JBqN4rXXXjPMgvHaa6+ZUri6ubkZ3//+97Fw4UJomoaFCxfi+9//Ppqbm02InDKFw2Fs374dsVgMUkrEYjFs374d4XA467YzZ9jQryvNmmFjeHgYf/EXf4FTp04hlUrh1KlT+Iu/+AsMDw9n3TYAlJSUTPn5es2ZMwehUMiwvkOhkCmzPpw7dw6hUMjwbncqjyN0nSbLTNj5xR4Q6p9A43K328x3M9p2+hAMJxXwCgaDsra21rBt1NbWmjZ2Vi9CqT9xMGuYBJ9K5U5vb6/0+XyGbcTn85myrgOBgJw9e7bhCfTs2bNlIBAwIXJn0tfxihUr5PHjx9Pzydv5OAIYh1hlfjb7e8zEIqhG+m+nD7HS3+287Unp3GsGMsrs/ao/OTer92sgEJAzZ840tD1z5kxTzjUAZHV1teE8Vl1dbdq1tsfjMVxH6dc92VI1vMjJxxH2yMw9cAhG/lGdgPjUpz5lSEB86lOfMq1bmFOLUObiItxM+slh/Bh8s7YRIYShbTPHhbOrXO6o2mcCgcCEF26FnoBwuVyG5Jo+VMquVJ5rxn+PmXjjaqSfD1TUe1GJiaT8oHJ/FEJM+NDCjCEYbrc7PSRUT274/X7pdruzblu/xhmfkDZr9g4Vx+1cnQ/MprIGCU2OCYg8BEAuWrTIcJO2aNEi024uVd1sO3kaTgCyrKxMapomy8rKbH/QFULI+vp6wzZSX19vWmVoVSchlU9K6EqqEhCc9upK+j6SOZ7Y7scRpyYgWAPCSP/N9ISX/m7nbU9KJpLyhcpEksokgcrjn6Zpsr6+3tBmfX29aVPMAlcW3DYrAaFpmnzjjTccMSOclGpnYaHJMQGRh4A/FYLRM3tmFYIZn3zIPOBkS+VFoeoM+0TrxM7ZUz1GFTOlqJwLOhAIyPLycsPFRHl5eUE/OVdF5XAX3jhcyYk3gXp8mecaJyQgpOQsGJmc+uSSiaT8oLILvH4sHT8NpxnbtsprP9VTzLpcLsN+Y8Y60f/7M68ZnHAcySxUmvlgy87X8PmACYg8pCcJxl/Impk5VXWhovKJq6oM+/gDbeZnu9JvGjJ7QOg3D9nSxxdmbn9mVoZWNeZSSt6UZKqsrJzwws2M35E9Wa7kxJvAzASE/juaFbMT14dT6TMJjX/5/X6rQ7sqHrOdT+W0zADkzTffbBg2fPPNN5t6jFLR+1V1r92JeoWYkYDweDyGBITdr4WlND7Y0hPpfLClHhMQeUg/kOiJCP3djIsJ4FIhuswDjF6ozs5UZ5N9Pp/h4GX3daKyBwRwaerGzG1En8LRjLY3bdpkWLZp0ybbn/CdSPW6duKUuyqp7F2mih6jimk4uT/mjhOT6JQ/gsGgXLJkiSFJsGTJEtOuzwDIiooKKYSQFRUVpl7rFBUVGc5jRUVFtn8gop9XzJ7iU1+vTirILiVrUlmFCYg8BECWlJQYDi4lJSWOOOCqkosaECpu5lURQshAIGA44eufs6VvI5nbn1nbiH6zk/k76jc92eKwACMA8sEHHzT0knnwwQe5rhXR90NVxVtVUNlLgdtI7uj7d+Yx26yZi4iuRghhSGDqCU0za1KpSJLq+0pmTwIzE3eqEhCqhsmOT5w7pdcaa1JZgwmIPARAtrS0GHamlpYWU7ucOWmqOJ3KbHLmSS3zs12pfiqgKiETCAQm7F1hRqaaFdWN9Jvf8T2pzLgo5Lq+EgC5atUqwzFq1apVtj6OSDlxEsIM3EZyx4lJdB2HYDgfAFlaWmp4sFBaWmra9YjKB3KqErAqH5plPnzSX/pDqGyoXB8qMdltDSYg8pB+s5D5JM2smSr0A9X4A5fdDzAqZd7MZ77beZ243W7DHM0A0suyBagbktLR0SE1TTM8KdE0zZSxosFgcMITZ6GehMbv35n7fbZ4wr+SfuzIvODUjyWFiNtI7ug9IDKf5DqhBwSH6eQHAHLmzJmGa4aZM2eads2qot6B3rYTe4ABkLt37zYs2717d9ZxBwKBCX9Huw9l4HHEGkxA5KHMaYf0g4DZ0w45aao41fT/fqdVr1eZpNJnYdFP+GbNwqK6Wrb+hGRgYMAxFZxV0W9KVHTL5gn/SiqLtzoRt5Hc0ZPGrO1kxN4VuaEySaBp2oTXOnYvyq66cLqKBETmAyJ9uItZD4hU476ee0xA5KHMKWUyC7yZ0XXa7XZPeFNiRnLDqZyYlAEgm5ubDQfc5uZmU2J2u92ytLTUsP2Vlpaaso3kYjaTzHVSyIXYAMi7777bsD7uvvtu09YHT/hGHR0dUgiR7pnkdrulEMIRF2+qcBvJDZUzZ6mk8nzABFjuaJomhRCGayghhCm/oxBiwumkzawvoeLaT2VyTVXRRZXFRCn/MAGRh1Q/JZ7oKZ0TbtJU1oAIBoOGYn16d3670ocvqCjmqGfBM0/KZg6TUNkt8Te/+Y1h2W9+8xtb/44q6RdSThwX7kQqj9tEU9GfNldUVEhN09JDf+w+DafK80EwGJQrV640nNdXrlzJ/VEBldeVKn9HPVGc+bBFTyBnS2UCrLe3V86YMcOQlJkxY0bWbevrY/x0qrxmoIkwAZGHVE5x59QeELmYBWN8sT47H3RVz3vc0dFhOOGb9RRX9e/o8/kMy5zQDVmVzKFEmS+Xy2V1aHmJlbjJKgBkTU2NYT/XP9uZ6vPBRN3J7b5OnMjr9cqFCxcanpwvXLhQer3erNtWWTdK5RAMKdU9NMu8R9CHvJhxj6BydjXKP0xA5CFVBxcp/5SpHj9dkt1PyiqflKicLUCV3t7eCbslmnmCU9V1WlXb+u/o8/nkb37zm3Tywc6/o0pO7u3kRIFAQM6ePdtwMzV79mzbF/Ai53PqeV1KtT0b9WLK+nVUISekVVLZ2y6zMKL+O5pVGFF1AkIVVdfD+n+7E2fJo9ybKgGhgRwpEolg9erV8Pv9AAC/34/Vq1cjEomY0n5xcTGKi4uhaVr6f9vd0NAQGhoaDMsaGhowNDSUddtSSpSUlGD+/PnQNA3z589HSUnJpSxeAYpGowiHw+js7EQ8HkdnZyfC4TCi0agp7Tc3N2NwcBBjY2MYHBxEc3OzKe2mUikIIRCPx/Hnf/7niMfjEEIglUqZ0r7TeL1eLF26FG63GwDgdruxdOlSeL1eiyPLX+OPGYV6DCFrrFu3DrFYDOvWrbM6lGum6nwAAIlEAqFQCOfOnUMoFEIikTCtbfoTIQQqKiqwbds2lJeXY9u2baioqIAQIuu2jxw5gvb2dsP1cHt7O44cOZJ1206l8np41qxZ2LVrF6qqqrBr1y7MmjUr6zapAE2WmbDziz0gLj3JnahbollFd5w4VZzq2gHf/OY3DU9hvvnNb9p6nah82srp8/KD3vshczyn3guCzMchGGQVALKsrMzwlLisrMzW5zDVAMh77rnHsD/ec889Bb1OVIHCJ+dQWO9KjzFzuKlZcaukugfE+Foydl8fZA2wB0T+KSoqwtKlSxEKheDz+RAKhbB06VIUFRWZ0n4qlUJrayu8Xi9aW1sd8YQ4HA6jra0N/f39SCaT6O/vR1tbG8LhcNZtu91u/OAHPzA88f/BD36QfnJsR0eOHMGPfvQjNDY2wuPxoLGxET/60Y9MeSqgMrsOXOphUV9fD5fLhfr6etN6VpBRUVERPvWpT+Hv//7v4ff78fd///f41Kc+ZdpxhIzq6urwn//5n4Zl//mf/4m6ujqLIqJC8uCDDxqeEj/44IMWR2S9t956C62trTh37hxaW1vx1ltvWR1S3qqurjY8Oa+urjalXbfbjWQyaViWTCZNvT7buXMnEokEdu7caVqbKoXDYaxatQq1tbVwuVyora3FqlWrTLsePn/+PFKpFM6fP2/r62CysckyE3Z+sQeENBRPQkbRHZg0nk5l8UKVVI0V1afPGz9W3s7T5wFq5oGWUm0PCE6NljtwYHFVJ1NZLI1oKpWVlRP2dqqsrLQ6NMsEAgFZVFRkGNdfVFTkiGsdp0HGk/PMdzPONUKIdO0O/eXz+UydhlNF3Cr19vZOuE7MmAVjshfReGARyvzjdrul3+83dKf0+/2mzFShssClU6ku6KhCZmEmPZFkVmEmlUkC1cM79Cmj9JfdZ3dRSV8HKuY4pysFAoH0MUR/eTwe3vCQck48h6mWmRDMnAWDCUHzjU9wZ37OVmVl5YQPiMxIrjn1hltfJ5nndjPWiVPXB1ljqgQEh2A41OjoKMrKytDT04N4PI6enh6UlZVhdHQ067abm5uxatUqfPTRR0ilUvjoo4+watUqUws/OU0kEsHLL7+MRCIBKSUSiQRefvll04p+qrBy5UqcO3cOFy9eBABcvHgR586dw8qVK7Nuu7m5GZFIxDAEKBKJmLKNqBze4fF4MDo6ioqKCrz//vuoqKjA6OgoPB5P1m07VUVFBXp7exGPx9Hb24uKigqrQ8pbR44cwejoaLpo16xZszA6OlrQxdIoN5qbm/G3f/u30LRLl32apuFv//ZvC/q83t/fj6eeego33ngjhBC48cYb8dRTT6G/v9/q0PJSKpVCaWkpAKC0tNS0ob1nzpyBEAKbNm1CLBbDpk2bIITAmTNnsm770j3UtS+3i+Hh4QnP7cPDw6a0v2LFChw/fhwrVqwwpT0qQJNlJuz8Yg8ImS7mk1kYRy/qk63MHhD6k/NC7wGhaZpMJBKGZYlEwtbF44LBoAyHw4YhKfpnO1MZNy53oczkhAKrqgCQq1atMqzrVatWFez6UA2ALC0tNfQcKi0t5fom5Xhev5ITz+tOBSA97av+MmsaWDiwSLhqAOQzzzxjWPbMM89kvU5wuedKZk8qs3qyUP4Be0Dkn8rKSrz22mvYsGEDYrEYNmzYgNdeew2VlZVZt71u3Tq4XC709PRgZGQEPT09cLlcjpq2y2x1dXUYGBgwLBsYGLB18bihoSHccssthmW33HKLaYUi9d4PQoh0LwgzNDY2YuPGjYbCYBs3bkRjY6Mp7Y8vMlbIRcc0TcNPf/pTw7r+6U9/mn5KSuZLJBJoampCUVERmpqaOO0f5QTP61dy4nndyYQQ2Lx5M2KxGDZv3mzKFJy68b3I2KsM2Lhxo6Eo+8aNG01pN5VKpYt+JpNJRxSpJxuaLDNh5xd7QBjH9+t1Gswa3w9APvnkk4Zs8pNPPlnQGU4nFkZUOQ2nymJ67AGRO3pxVb0uhtvttn1xVSdDRkEzIYRjCpqR80FhUWKncuJ53amgsAaE3++XAGR7e7s8ffq0bG9vlwCk3+83IXJn0mtAZF6jmVkDIhgMykOHDslgMMhzGE0KLEKZf1TOJw9gwuKFhX6AUTXDhiqBQEBWV1cbLq6qq6tNSUC43W5ZUVFhaLuiosKUgo4qu8XqN9oVFRXy/fffT98AFnIhyo6ODsNQLiYf1NEv1DKLpfHijXKBCYiJOe287lSZiYfxr2wFAgFZUlJiGBZQUlJS0MV9e3t75YwZMwzrZMaMGZwFg3KKCYg8pHKmAE3TpKZphum69GXkHKqTVKrGXHIWDMpXmdtc5jsv3kg1lT3iiK5G5Y2rymsdJ1ORXGMCgqZjqgQEB/o6VDgcRltbm2F8V1tbG8LhcNZt65WKOzs7UVZWhs7OTlMrFlNu1NXVIRAIYHBwEGNjYxgcHEQgEDBtfOsPfvADdHZ2Ih6Po7OzEz/4wQ9MaTccDmPVqlWora2Fy+VCbW0tVq1aZcq2DVwas5h5ENTHMhKpJoTAvffei1tuuQWapuGWW27Bvffea+pYaKKJbNq0CaOjo2htbYXP50NraytGR0exadMmq0Mjyorqax2nam5uNqwTM2e8KS0txbvvvpue1YRoupiAcCiV0yACwN13322YhvPuu+82pV3KncwbeU3TTL2R1zQNZ86cwXvvvYdkMon33nsPZ86cMb144aUEKqkUjUZRX18Pl8uF+vp6RKNRq0PKW1JKvPXWW4ain2+99Ra3c1KO02uTHQSDQWiahmAwaFqbKh/I0cT8fj+WLFkCv99vdSjkVJN1jbDzi0Mw1KqsrJQul8swBMPlcmVdvIZyK3PaNb1QqVnTrgkhpM/nM3S/8/l8UgiRdduqh2DQn7AIW24Fg0G5ZMmS9PRzQgi5ZMkSbtukHPd1spJ+nTC+UCRM6rrv1FoeThsSCkDeeeedhnPYnXfeySEYNCGwBgRNRyAQkOXl5YYb1/Lyco4VdRiVN/IqZ2HheM7cUTnjCF2po6NDut1uQ3LX7Xaz8Ccpx8QuWQmsHXAFJxbF1n+zzGu/Qv8daXJTJSCEdGDXzyVLlsg9e/ZYHUbecrlc+NrXvpaeL9zr9aK1tRXf//73MTY2ZnV4dI1cLhfi8Tg8Hk96WTKZhM/ny/p3nDdvHsbGxvDiiy+ioaEBAwMDePjhh+FyufDhhx9m3fbo6Ch6e3vTbbe0tMDtdmfdNnBpyEEkEsHQ0BDq6uoQDocLthuypmlYsGABenp60uu6tbUVhw4dYs0XBerr67Fy5Uq89NJL6e1P/zw4OGh1eJTHVJ4PiK5mqjo3TrwPMYMQAhUVFRgeHk4vq6ysxKlTp2y7TvTfUQhx6Sby8jtQuL8jTU4I8a6UcslE/8YaEHSFOXPmIBqNYvbs2RBCYPbs2YhGo5gzZ47VoVnKaWPl6+rqMDAwYFg2MDBgSmGmY8eOYePGjYYaJBs3bsSxY8eybhu48mLFrCJ90WgU4XDYUDwzHA7b/rdUpaioCKFQCI2NjfB4PGhsbEQoFEJRUZHVoeWloaEh3HLLLYZlt9xyC4aGhiyKiAqFyvOBk+nnMCFE+lxG5pvs5tSsm1anXZ/p3nrrrSk/2xWTDpS1ybpG2PnFIRhqVVZWTjgNZyHXgHDi+FmVMaueBlbVEAx2QzYSQky4jZhRy4OuFAgEZHV1tWF9V1dXc3gbKefEc5hqHBKVH5y6bePy8ItM+jAMM6ioLwFAbtq0ybBs06ZNHIJBEwJrQNB0AJBPPvmk4QbwySefLOgDjFNvXFUVZlJZ4FJ1ciORSBiWJRKJgq0vwRoQuRUIBOTs2bMNF8qzZ89mAoJywqmF+lTxer1y8+bNhmWbN2+WXq/Xoojoejj1+kxlDQhVbeNywXGPxyMBSI/Hky5ITjQeExA0LQDk7t27Dct2795d0AcY3rgaZSYghBCmJiCc2nPDiZz65MipNE2T7e3t0uv1SgDS6/XK9vb2gj2OEFkJgIzFYoZlsVisoK91nMjJ12eqZsFQ1bvC7/en28589/v9WbVL+YkJCJoWPqW7Em9cjVSvD5U9N3jDbcSnornDIRhE9uH1euXDDz9sOP49/PDD7AHhMLw+uxIA+f777xuWvf/++1knINxutywtLTU8fCotLbX1zB1kHUsSEAD+EcBRAL+9/Hpgkr/7IoD/BLAfwJPX0jYTEGqp7F7vVLxxNXLyVJm84SarMLlLZB/Lli2b8GnusmXLrA6NpoHXZ1dS1QMCgPzhD39ouIb64Q9/yF5DNCErExB/f5W/cQH4nwD+NwBFAH4HYNHV2mYCQj3epF2J6+RP+CSXaPqcnLgj5+M5zCgQCMji4mLDePbi4mKexxyI27aRqhoQrJtC0zFVAsJ9/fNnmOJ/B7BfSvm/AEAI8f8B8BCAfZZGRWhubkZzc7PVYdgK14lRPB5Ha2srDh06hAULFiAej6O0tNTqsIhsq66uDoFAAIODg+ll/f39BT8VIqkXjUbx+OOPw+/3AwBisRgef/xxACjY89qRI0ewe/du3H///ellr7/+OpYtW2ZhVHQ9eH1mlEwm4fF4cOrUKdx6660AALfbjWQymVW7jz76KNavXw8AWLNmDbq6urB+/XqsWbMm65ipsGiK2+8QQrwvhOgRQlRM8O9zAXyY8fnI5WVEZGNHjx6F230pfymEAHDp5Hb06FErwyKytXA4jLa2NvT39yOZTKK/vx9tbW0Ih8NWh0Z5bt26dXC73ejp6UE8HkdPTw/cbjfWrVtndWhEWYtGo6ivr4fL5UJ9fT2i0ajVIVkumUwanjhnm3wAgM7OTsyYMQNr166F3+/H2rVrMWPGDHR2dpoQMRWSrBIQQog3hBCDE7weArANwKcA3AbgIwCbs/yu1UKIPUKIPcePH8+mKboGPJjTVIqKivDUU0/hwIEDGBsbw4EDB/DUU0+hqKjI6tCIbKu5uRmRSAShUAg+nw+hUAiRSIRP7ki5I0eO4Ec/+hEaGxvh8XjQ2NiIH/3oRzhy5IjVoVkmEAjgK1/5Cmpra6FpGmpra/GVr3wFgUDA6tBoGqLRKMLhMDo7OxGPx9HZ2YlwOMzrVgVuvfVWDA8PY8WKFTh+/DhWrFiB4eHhdC8LomuVVQJCSnmflLJ+gtfLUspPpJRjUsoUgOdxabjFeEcBzMv4HLi8bKLv2i6lXCKlXFJVVZVN2HQVPJjT1SQSCWzdutXwJHfr1q1IJBJWh0bTxGRjbjU3N2NwcBBjY2MYHBxk8oFypq+vz7Cv9/X1WR2SpVauXImzZ88iHo9DCIF4PI6zZ89i5cqVVodG0xCJRNDd3W1IrnV3dyMSiVgdWt754IMPsGLFCrz88su48cYb8fLLL2PFihX44IMPrA6NHEZcqhGhoGEhZkspP7r8v/8rgDullH897m/cAH4P4F5cSjz8O4AWKeXeqdpesmSJ3LNnj5K4Caivr0dnZycaGxvTy/r7+xEKhQxjl6lw1dfXY+XKlXjppZcwNDSEurq69GduI86hJxu7u7vR0NCAgYEBtLW18ak8UZ654YYbcPr0aXznO99Jj93+5je/ifLycpw8edLq8CzB81h+cLlciMfj8Hg86WXJZBI+nw9jY2MWRpZ/hBA4fvw4brzxxvSyEydOoKqqCqruJ8m5hBDvSimXTPiPk1WnzPYF4McAPgDwPoBXAMy+vHwOgF9m/N0DuJSE+J8AwtfSNmfBUEvTNJlIJAzLEokEK7VTGqe9yg+cPz33WK2drBAIBGR5ebmsqamRQghZU1Mjy8vLC3rGB17r5Aeex3IHgFyxYoVh2YoVKzgNJ00IU8yCoawIpZTyb6SUi6WUt0opV8jLvSGklMeklA9k/N0vpZQLpZSfklKyv5QN1NXVYWBgwLBsYGCAldopjWPZ88PQ0BAaGhoMyxoaGjA0NGRRRPmNw9vIKseOHcN3v/td+P1+CCHg9/vx3e9+F8eOHbM6NMvwWic/hMNhrFq1ylDLY9WqVSzuq8DixYvxyiuv4KGHHsKJEyfw0EMP4ZVXXsHixYutDo0cRvUsGORArNRO18KpY9n1pIkQIp08KVS8AM+tSCSClpYWQ+KupaWFY5VJucwpYPVjdiAQKOh9ndc6+UeflYvUeP/999NJiKqqqnTy4f3337c6NHKaybpG2PnFIRjqsZsw5aOOjg7pdrvl5s2bZSwWk5s3b5Zut1t2dHRYHZolOJQmt4QQE65vIYTVoVGe474+MV7rOB+HYOQW9xm6VphiCIayIpQqsQglEV0Pn8+HL3/5y/jtb3+bLjp222234Wc/+xni8bjV4VkiGo0iEomk10c4HHZMbxan8fl82LBhA5544on0smeffRZPP/10wW5/lDvc1ykfsQhl7rBwNU3HVEUomYAgooIhhEBNTQ16enrSJ8/W1lYcPHiQFZxJOU3TsGDBgiu2v0OHDiGVSlkdHhGR43DmttzhuqbpmCoBwRoQRFQwhBBYvny5Yb7w5cuXc9wo5cSiRYtw2223Yfny5SgqKsLy5ctx2223YdGiRVaHRkTkSKzlkTssXE1mYQKCiApKV1cXZs+eDZfLhdmzZ6Orq8vqkKhANDY24tVXX8WGDRsQi8WwYcMGvPrqq4anSUSqCCGueBE5HWflyh0WriazMAFBRAVj7ty5KC4uxsmTJ5FKpXDy5EkUFxdj7ty5VodGBaC/vx/r169HT08PysrK0NPTg/Xr16O/v9/q0CjPZSYb/ut//a8TLidyKqfOyuU07G1CZmENCCIqGPPmzcPo6Ch6e3vTY/BbWlrgdrvx4YcfWh0e5TkWSyOr6ImGzGu+iZYREU2FxWzpWrEGBBERgGPHjmHTpk2GrpqbNm3CsWPHrA6NCgC7r5KVMns+TPSZiOhq2NuEzMAEBBEVjLq6OgQCAcPJMxAI8AaQcoLdV8lK/+2//bcpPxMRXU1TUxM0TYMQApqmoampyeqQyIGYgCCigsEbQLISi6WR1YQQeOKJJ1j7gfJKNBpFfX09XC4X6uvrEY1GrQ4pLzU1NWH37t1Ys2YNTp8+jTVr1mD37t1MQtC0sQYEERUUjl8kokI0UdLBideARJmi0SjC4TC6u7vTtZ3a2tqY3FVA0zSsWbMGzz33XHrZY489hq6uLqRSKQsjIzuaqgYEExBEREREROQ49fX16OzsNExn3N/fj1AohMHBQQsjyz9CCJw+fRozZ85MLztz5gzKy8uZzKQrsAglERERERHllaGhIRw5csQwBOPIkSMYGhqyOrS8I4TAU089ZVj21FNPcUgXTZvb6gCIiIiIiIima86cOVi/fj1efPHF9BCMhx9+GHPmzLE6tLxz//33Y9u2bQCAZ555Bk899RS2bduGZcuWWRwZOQ0TEERERERE5Ejju/9zOIAau3btQlNTE7q6urBt2zYIIbBs2TLs2rXL6tDIYTgEg4iIKEdYrZ2IyDzHjh3Dpk2bDLMLbdq0CceOHbM6tLy0a9cupFIpSCmRSqWYfKDrwh4QREREOTBZtXYArNZORHQd6urqEAgEDAUn+/v7UVdXZ2FURDQV9oAgIiLKgUgkgu7ubjQ2NsLj8aCxsRHd3d2IRCJWh0ZE5EjhcBhtbW3o7+9HMplEf38/2traEA6HrQ6NiCbBaTiJiIhywOVyIR6Pw+PxpJclk0n4fD6MjY1ZGBkRkXNFo1FEIhEMDQ2hrq4O4XCYvcqILDbVNJwcgkFERJQDdXV1GBgYMMxXPzAwwK7CRERZaG5uZsKByEE4BIOICgqLAJJV2FWYiIiICh17QBBRwWARQLKSvo2FQqF0V+FIJMJtj4iIiAoGa0AQUcGor69HZ2enoQt8f38/QqGQoYI2ERERERFdn6lqQDABQUQFg0UAiYiIiIjUmioBwRoQRFQw9CKAmVgEkIiIiIgoN1gDgogKRjgcxgMPPIB4PJ5e5vP50NPTY2FURERERESFgT0giKhgvPDCC4jH46ioqAAAVFRUIB6P44UXXrA2MCIiIiKiAsAeEERUMF5//XXcd999+Oijj3DmzBnMmTMHd9xxB15//XWrQyMiIiIiynvsAUFEBUNKiT/84Q/o7OxEPB5HZ2cn/vCHP8CJxXiJiIiIiJyGCQgiKiif/exn0djYCI/Hg8bGRnz2s5+1OiQiIiIiooLABAQRFZRXXnkFjz32GM6cOYPHHnsMr7zyitUhEREREREVBNaAIKKCEQwGUVxcjK6uLmzbtg1CCCxZsgQXL160OjQiIiIiorzHHhBEVDDC4TBOnjyJN998E4lEAm+++SZOnjyJcDhsdWhERERERHmPPSCIqGA0NzcDAEKhEIaGhlBXV4dIJJJeTkRERERE6ggnVn9fsmSJ3LNnj9VhEBEREREREVEGIcS7UsolE/0bh2AQERERERERkXJMQBARERERERGRckxAEBEREREREZFyTEAQERERERERkXJMQBARERERERGRckxAEBEREREREZFyTEAQUUGJRqOor6+Hy+VCfX09otGo1SERERERERUEt9UBEBHlSjQaRTgcRnd3NxoaGjAwMIC2tjYAQHNzs8XRERERERHlNyGltDqGaVuyZIncs2eP1WEQkcPU19ejs7MTjY2N6WX9/f0IhUIYHBy0MDIiIiIiovwghHhXSrlkwn9jAoKICoXL5UI8HofH40kvSyaT8Pl8GBsbszAyIiIiIqL8MFUCgjUgiKhg1NXVYWBgwLBsYGAAdXV1FkVERERERFQ4mIAgooIRDofR1taG/v5+JJNJ9Pf3o62tDeFw2OrQiIiIiIjyHotQElHB0AtNhkIhDA0Noa6uDpFIhAUoiYiIiIhygDUgiIiIiIiIiMgUrAFBRERERERERJZSNgRDCLEDwC2XP5YDOC2lvG2CvzsI4ByAMQCjk2VKiIiIiIiIiMi5lCUgpJSr9P8thNgM4MwUf94opTyhKhYiIiIiIiIispbyIpRCCAHgKwDuUf1dRERERERERGRPuZgF4/8B4BMp5R8m+XcJYLcQQgL4vpRyew5issbdd1sdARERERERETnFr35ldQSmyioBIYR4A0D1BP8UllK+fPl/NwOITtFMg5TyqBDiJgCvCyH+h5Ty1xN812oAqwFg/vz52YRNRERERERERDmmdBpOIYQbwFEAd0gpj1zD3/8jgPNSyn+e6u84DScR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\n",
      "text/plain": [
       "<Figure size 1296x720 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(18, 10))\n",
    "plt.boxplot(x=train_data.values,labels=train_data.columns)\n",
    "plt.hlines([-7.5, 7.5], 0, 40, colors='r')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 删除异常值\n",
    "train_data = train_data[train_data['V9']>-7.5]\n",
    "test_data = test_data[test_data['V9']>-7.5]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# stacking特征"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## stacking回归特征"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "-- 回归\n",
    "-- stacking 回归特征\n",
    "\"\"\"\n",
    "def stacking_reg(clf,train_x,train_y,test_x,clf_name,kf,label_split=None):\n",
    "    train=np.zeros((train_x.shape[0],1))\n",
    "    test=np.zeros((test_x.shape[0],1))\n",
    "    test_pre=np.empty((folds,test_x.shape[0],1))\n",
    "    cv_scores=[]\n",
    "    for i,(train_index,test_index) in enumerate(kf.split(train_x,label_split)):       \n",
    "        tr_x=train_x[train_index]\n",
    "        tr_y=train_y[train_index]\n",
    "        te_x=train_x[test_index]\n",
    "        te_y = train_y[test_index]\n",
    "        if clf_name in [\"rf\",\"ada\",\"gb\",\"et\",\"lr\"]:\n",
    "            clf.fit(tr_x,tr_y)\n",
    "            pre=clf.predict(te_x).reshape(-1,1)\n",
    "            train[test_index]=pre\n",
    "            test_pre[i,:]=clf.predict(test_x).reshape(-1,1)\n",
    "            cv_scores.append(mean_squared_error(te_y, pre))\n",
    "        elif clf_name in [\"xgb\"]:\n",
    "            train_matrix = clf.DMatrix(tr_x, label=tr_y, missing=-1)\n",
    "            test_matrix = clf.DMatrix(te_x, label=te_y, missing=-1)\n",
    "            z = clf.DMatrix(test_x, label=te_y, missing=-1)\n",
    "            params = {'booster': 'gbtree',\n",
    "                      'eval_metric': 'rmse',\n",
    "                      'gamma': 1,\n",
    "                      'min_child_weight': 1.5,\n",
    "                      'max_depth': 5,\n",
    "                      'lambda': 10,\n",
    "                      'subsample': 0.7,\n",
    "                      'colsample_bytree': 0.7,\n",
    "                      'colsample_bylevel': 0.7,\n",
    "                      'eta': 0.03,\n",
    "                      'tree_method': 'exact',\n",
    "                      'seed': 2017,\n",
    "                      'nthread': 12\n",
    "                      }\n",
    "            num_round = 10000\n",
    "            early_stopping_rounds = 100\n",
    "            watchlist = [(train_matrix, 'train'),\n",
    "                         (test_matrix, 'eval')\n",
    "                         ]\n",
    "            if test_matrix:\n",
    "                model = clf.train(params, train_matrix, num_boost_round=num_round,evals=watchlist,\n",
    "                                  early_stopping_rounds=early_stopping_rounds\n",
    "                                  )\n",
    "                pre= model.predict(test_matrix,ntree_limit=model.best_ntree_limit).reshape(-1,1)\n",
    "                train[test_index]=pre\n",
    "                test_pre[i, :]= model.predict(z, ntree_limit=model.best_ntree_limit).reshape(-1,1)\n",
    "                cv_scores.append(mean_squared_error(te_y, pre))\n",
    "\n",
    "        elif clf_name in [\"lgb\"]:\n",
    "            train_matrix = clf.Dataset(tr_x, label=tr_y)\n",
    "            test_matrix = clf.Dataset(te_x, label=te_y)\n",
    "            params = {\n",
    "                      'boosting_type': 'gbdt',\n",
    "                      'objective': 'regression_l2',\n",
    "                      'metric': 'mse',\n",
    "                      'min_child_weight': 1.5,\n",
    "                      'num_leaves': 2**5,\n",
    "                      'lambda_l2': 10,\n",
    "                      'subsample': 0.7,\n",
    "                      'colsample_bytree': 0.7,\n",
    "                      'colsample_bylevel': 0.7,\n",
    "                      'learning_rate': 0.03,\n",
    "                      'tree_method': 'exact',\n",
    "                      'seed': 2017,\n",
    "                      'nthread': 12,\n",
    "                      'silent': True,\n",
    "                      }\n",
    "            num_round = 10000\n",
    "            early_stopping_rounds = 100\n",
    "            if test_matrix:\n",
    "                model = clf.train(params, train_matrix,num_round,valid_sets=test_matrix,\n",
    "                                  early_stopping_rounds=early_stopping_rounds\n",
    "                                  )\n",
    "                pre= model.predict(te_x,num_iteration=model.best_iteration).reshape(-1,1)\n",
    "                train[test_index]=pre\n",
    "                test_pre[i, :]= model.predict(test_x, num_iteration=model.best_iteration).reshape(-1,1)\n",
    "                cv_scores.append(mean_squared_error(te_y, pre))\n",
    "        else:\n",
    "            raise IOError(\"Please add new clf.\")\n",
    "        print(\"%s now score is:\"%clf_name,cv_scores)\n",
    "    test[:]=test_pre.mean(axis=0)\n",
    "    print(\"%s_score_list:\"%clf_name,cv_scores)\n",
    "    print(\"%s_score_mean:\"%clf_name,np.mean(cv_scores))\n",
    "    return train.reshape(-1,1),test.reshape(-1,1)\n",
    "\n",
    "def rf_reg(x_train, y_train, x_valid, kf, label_split=None):\n",
    "    randomforest = RandomForestRegressor(n_estimators=600, max_depth=20, n_jobs=-1, random_state=2017, max_features=\"auto\",verbose=1)\n",
    "    rf_train, rf_test = stacking_reg(randomforest, x_train, y_train, x_valid, \"rf\", kf, label_split=label_split)\n",
    "    return rf_train, rf_test,\"rf_reg\"\n",
    "\n",
    "def ada_reg(x_train, y_train, x_valid, kf, label_split=None):\n",
    "    adaboost = AdaBoostRegressor(n_estimators=30, random_state=2017, learning_rate=0.01)\n",
    "    ada_train, ada_test = stacking_reg(adaboost, x_train, y_train, x_valid, \"ada\", kf, label_split=label_split)\n",
    "    return ada_train, ada_test,\"ada_reg\"\n",
    "\n",
    "def gb_reg(x_train, y_train, x_valid, kf, label_split=None):\n",
    "    gbdt = GradientBoostingRegressor(learning_rate=0.04, n_estimators=100, subsample=0.8, random_state=2017,max_depth=5,verbose=1)\n",
    "    gbdt_train, gbdt_test = stacking_reg(gbdt, x_train, y_train, x_valid, \"gb\", kf, label_split=label_split)\n",
    "    return gbdt_train, gbdt_test,\"gb_reg\"\n",
    "\n",
    "def et_reg(x_train, y_train, x_valid, kf, label_split=None):\n",
    "    extratree = ExtraTreesRegressor(n_estimators=600, max_depth=35, max_features=\"auto\", n_jobs=-1, random_state=2017,verbose=1)\n",
    "    et_train, et_test = stacking_reg(extratree, x_train, y_train, x_valid, \"et\", kf, label_split=label_split)\n",
    "    return et_train, et_test,\"et_reg\"\n",
    "\n",
    "def lr_reg(x_train, y_train, x_valid, kf, label_split=None):\n",
    "    lr_reg=LinearRegression(n_jobs=-1)\n",
    "    lr_train, lr_test = stacking_reg(lr_reg, x_train, y_train, x_valid, \"lr\", kf, label_split=label_split)\n",
    "    return lr_train, lr_test, \"lr_reg\"\n",
    "\n",
    "def xgb_reg(x_train, y_train, x_valid, kf, label_split=None):\n",
    "    xgb_train, xgb_test = stacking_reg(xgboost, x_train, y_train, x_valid, \"xgb\", kf, label_split=label_split)\n",
    "    return xgb_train, xgb_test,\"xgb_reg\"\n",
    "\n",
    "def lgb_reg(x_train, y_train, x_valid, kf, label_split=None):\n",
    "    lgb_train, lgb_test = stacking_reg(lightgbm, x_train, y_train, x_valid, \"lgb\", kf, label_split=label_split)\n",
    "    return lgb_train, lgb_test,\"lgb_reg\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## stacking 分类特征"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "-- 分类\n",
    "-- stacking 分类特征\n",
    "\"\"\"\n",
    "def stacking_clf(clf,train_x,train_y,test_x,clf_name,kf,label_split=None):\n",
    "    train=np.zeros((train_x.shape[0],1))\n",
    "    test=np.zeros((test_x.shape[0],1))\n",
    "    test_pre=np.empty((folds,test_x.shape[0],1))\n",
    "    cv_scores=[]\n",
    "    for i,(train_index,test_index) in enumerate(kf.split(train_x,label_split)):       \n",
    "        tr_x=train_x[train_index]\n",
    "        tr_y=train_y[train_index]\n",
    "        te_x=train_x[test_index]\n",
    "        te_y = train_y[test_index]\n",
    "\n",
    "        if clf_name in [\"rf\",\"ada\",\"gb\",\"et\",\"lr\",\"knn\",\"gnb\"]:\n",
    "            clf.fit(tr_x,tr_y)\n",
    "            pre=clf.predict_proba(te_x)\n",
    "            \n",
    "            train[test_index]=pre[:,0].reshape(-1,1)\n",
    "            test_pre[i,:]=clf.predict_proba(test_x)[:,0].reshape(-1,1)\n",
    "            \n",
    "            cv_scores.append(log_loss(te_y, pre[:,0].reshape(-1,1)))\n",
    "        elif clf_name in [\"xgb\"]:\n",
    "            train_matrix = clf.DMatrix(tr_x, label=tr_y, missing=-1)\n",
    "            test_matrix = clf.DMatrix(te_x, label=te_y, missing=-1)\n",
    "            z = clf.DMatrix(test_x, label=te_y, missing=-1)\n",
    "            params = {'booster': 'gbtree',\n",
    "                      'objective': 'multi:softprob',\n",
    "                      'eval_metric': 'mlogloss',\n",
    "                      'gamma': 1,\n",
    "                      'min_child_weight': 1.5,\n",
    "                      'max_depth': 5,\n",
    "                      'lambda': 10,\n",
    "                      'subsample': 0.7,\n",
    "                      'colsample_bytree': 0.7,\n",
    "                      'colsample_bylevel': 0.7,\n",
    "                      'eta': 0.03,\n",
    "                      'tree_method': 'exact',\n",
    "                      'seed': 2017,\n",
    "                      \"num_class\": 2\n",
    "                      }\n",
    "\n",
    "            num_round = 10000\n",
    "            early_stopping_rounds = 100\n",
    "            watchlist = [(train_matrix, 'train'),\n",
    "                         (test_matrix, 'eval')\n",
    "                         ]\n",
    "            if test_matrix:\n",
    "                model = clf.train(params, train_matrix, num_boost_round=num_round,evals=watchlist,\n",
    "                                  early_stopping_rounds=early_stopping_rounds\n",
    "                                  )\n",
    "                pre= model.predict(test_matrix,ntree_limit=model.best_ntree_limit)\n",
    "                train[test_index]=pre[:,0].reshape(-1,1)\n",
    "                test_pre[i, :]= model.predict(z, ntree_limit=model.best_ntree_limit)[:,0].reshape(-1,1)\n",
    "                cv_scores.append(log_loss(te_y, pre[:,0].reshape(-1,1)))\n",
    "        elif clf_name in [\"lgb\"]:\n",
    "            train_matrix = clf.Dataset(tr_x, label=tr_y)\n",
    "            test_matrix = clf.Dataset(te_x, label=te_y)\n",
    "            params = {\n",
    "                      'boosting_type': 'gbdt',\n",
    "                      #'boosting_type': 'dart',\n",
    "                      'objective': 'multiclass',\n",
    "                      'metric': 'multi_logloss',\n",
    "                      'min_child_weight': 1.5,\n",
    "                      'num_leaves': 2**5,\n",
    "                      'lambda_l2': 10,\n",
    "                      'subsample': 0.7,\n",
    "                      'colsample_bytree': 0.7,\n",
    "                      'colsample_bylevel': 0.7,\n",
    "                      'learning_rate': 0.03,\n",
    "                      'tree_method': 'exact',\n",
    "                      'seed': 2017,\n",
    "                      \"num_class\": 2,\n",
    "                      'silent': True,\n",
    "                      }\n",
    "            num_round = 10000\n",
    "            early_stopping_rounds = 100\n",
    "            if test_matrix:\n",
    "                model = clf.train(params, train_matrix,num_round,valid_sets=test_matrix,\n",
    "                                  early_stopping_rounds=early_stopping_rounds\n",
    "                                  )\n",
    "                pre= model.predict(te_x,num_iteration=model.best_iteration)\n",
    "                train[test_index]=pre[:,0].reshape(-1,1)\n",
    "                test_pre[i, :]= model.predict(test_x, num_iteration=model.best_iteration)[:,0].reshape(-1,1)\n",
    "                cv_scores.append(log_loss(te_y, pre[:,0].reshape(-1,1)))\n",
    "        else:\n",
    "            raise IOError(\"Please add new clf.\")\n",
    "        print(\"%s now score is:\"%clf_name,cv_scores)\n",
    "    test[:]=test_pre.mean(axis=0)\n",
    "    print(\"%s_score_list:\"%clf_name,cv_scores)\n",
    "    print(\"%s_score_mean:\"%clf_name,np.mean(cv_scores))\n",
    "    return train.reshape(-1,1),test.reshape(-1,1)\n",
    "\n",
    "def rf_clf(x_train, y_train, x_valid, kf, label_split=None):\n",
    "    randomforest = RandomForestClassifier(n_estimators=1200, max_depth=20, n_jobs=-1, random_state=2017, max_features=\"auto\",verbose=1)\n",
    "    rf_train, rf_test = stacking_clf(randomforest, x_train, y_train, x_valid, \"rf\", kf, label_split=label_split)\n",
    "    return rf_train, rf_test,\"rf\"\n",
    "\n",
    "def ada_clf(x_train, y_train, x_valid, kf, label_split=None):\n",
    "    adaboost = AdaBoostClassifier(n_estimators=50, random_state=2017, learning_rate=0.01)\n",
    "    ada_train, ada_test = stacking_clf(adaboost, x_train, y_train, x_valid, \"ada\", kf, label_split=label_split)\n",
    "    return ada_train, ada_test,\"ada\"\n",
    "\n",
    "def gb_clf(x_train, y_train, x_valid, kf, label_split=None):\n",
    "    gbdt = GradientBoostingClassifier(learning_rate=0.04, n_estimators=100, subsample=0.8, random_state=2017,max_depth=5,verbose=1)\n",
    "    gbdt_train, gbdt_test = stacking_clf(gbdt, x_train, y_train, x_valid, \"gb\", kf, label_split=label_split)\n",
    "    return gbdt_train, gbdt_test,\"gb\"\n",
    "\n",
    "def et_clf(x_train, y_train, x_valid, kf, label_split=None):\n",
    "    extratree = ExtraTreesClassifier(n_estimators=1200, max_depth=35, max_features=\"auto\", n_jobs=-1, random_state=2017,verbose=1)\n",
    "    et_train, et_test = stacking_clf(extratree, x_train, y_train, x_valid, \"et\", kf, label_split=label_split)\n",
    "    return et_train, et_test,\"et\"\n",
    "\n",
    "def xgb_clf(x_train, y_train, x_valid, kf, label_split=None):\n",
    "    xgb_train, xgb_test = stacking_clf(xgboost, x_train, y_train, x_valid, \"xgb\", kf, label_split=label_split)\n",
    "    return xgb_train, xgb_test,\"xgb\"\n",
    "\n",
    "def lgb_clf(x_train, y_train, x_valid, kf, label_split=None):\n",
    "    xgb_train, xgb_test = stacking_clf(lightgbm, x_train, y_train, x_valid, \"lgb\", kf, label_split=label_split)\n",
    "    return xgb_train, xgb_test,\"lgb\"\n",
    "\n",
    "def gnb_clf(x_train, y_train, x_valid, kf, label_split=None):\n",
    "    gnb=GaussianNB()\n",
    "    gnb_train, gnb_test = stacking_clf(gnb, x_train, y_train, x_valid, \"gnb\", kf, label_split=label_split)\n",
    "    return gnb_train, gnb_test,\"gnb\"\n",
    "\n",
    "def lr_clf(x_train, y_train, x_valid, kf, label_split=None):\n",
    "    logisticregression=LogisticRegression(n_jobs=-1,random_state=2017,C=0.1,max_iter=200)\n",
    "    lr_train, lr_test = stacking_clf(logisticregression, x_train, y_train, x_valid, \"lr\", kf, label_split=label_split)\n",
    "    return lr_train, lr_test, \"lr\"\n",
    "\n",
    "def knn_clf(x_train, y_train, x_valid, kf, label_split=None):\n",
    "    kneighbors=KNeighborsClassifier(n_neighbors=200,n_jobs=-1)\n",
    "    knn_train, knn_test = stacking_clf(kneighbors, x_train, y_train, x_valid, \"lr\", kf, label_split=label_split)\n",
    "    return knn_train, knn_test, \"knn\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 获取数据\n",
    "features_columns = [c for c in all_data_test.columns if c not in ['label', 'prob', 'seller_path', 'cat_path', 'brand_path', 'action_type_path', 'item_path', 'time_stamp_path']]\n",
    "x_train = all_data_test[~all_data_test['label'].isna()][features_columns].values\n",
    "y_train = all_data_test[~all_data_test['label'].isna()]['label'].values\n",
    "x_valid = all_data_test[all_data_test['label'].isna()][features_columns].values\n",
    "\n",
    "#  处理函数值inf以及nan情况\n",
    "def get_matrix(data):\n",
    "    where_are_nan = np.isnan(data)\n",
    "    where_are_inf = np.isinf(data)\n",
    "    data[where_are_nan] = 0\n",
    "    data[where_are_inf] = 0\n",
    "    return data\n",
    "\n",
    "x_train = np.float_(get_matrix(np.float_(x_train)))\n",
    "y_train = np.int_(y_train)\n",
    "x_valid = x_train"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 导入划分数据函数 设stacking特征为5折\n",
    "from sklearn.model_selection import StratifiedKFold, KFold\n",
    "folds = 5\n",
    "seed = 1\n",
    "kf = KFold(n_splits=5, shuffle=True, random_state=0)\n",
    "\n",
    "\n",
    "# 使用lgb和xgb分类模型构造stacking特征\n",
    "\n",
    "# clf_list = [lgb_clf, xgb_clf, lgb_reg, xgb_reg]\n",
    "# clf_list_col = ['lgb_clf', 'xgb_clf', 'lgb_reg', 'xgb_reg']\n",
    "clf_list = [lgb_clf, xgb_clf]\n",
    "clf_list_col = ['lgb_clf', 'xgb_clf']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 训练模型，获取stacking特征\n",
    "\n",
    "clf_list = clf_list\n",
    "column_list = []\n",
    "train_data_list=[]\n",
    "test_data_list=[]\n",
    "for clf in clf_list:\n",
    "    train_data,test_data,clf_name=clf(x_train, y_train, x_valid, kf, label_split=None)\n",
    "    train_data_list.append(train_data)\n",
    "    test_data_list.append(test_data)\n",
    "train_stacking = np.concatenate(train_data_list, axis=1)\n",
    "test_stacking = np.concatenate(test_data_list, axis=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 原始特征和stacking特征合并\n",
    "train = pd.DataFrame(np.concatenate([x_train, train_stacking], axis=1))\n",
    "test = np.concatenate([x_valid, test_stacking], axis=1)\n",
    "\n",
    "# 特征重命名\n",
    "df_train_all = pd.DataFrame(train)\n",
    "df_train_all.columns = features_columns + clf_list_col\n",
    "df_test_all = pd.DataFrame(test)\n",
    "df_test_all.columns = features_columns + clf_list_col"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 获取数据ID以及特征标签LABEL\n",
    "df_train_all['user_id'] = all_data_test[~all_data_test['label'].isna()]['user_id']\n",
    "df_test_all['user_id'] = all_data_test[all_data_test['label'].isna()]['user_id']\n",
    "df_train_all['label'] = all_data_test[~all_data_test['label'].isna()]['label']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 训练数据和测试数据保存\n",
    "df_train_all.to_csv('train_all.csv',header=True,index=False)\n",
    "df_test_all.to_csv('test_all.csv',header=True,index=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 特征选择"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在机器学习和统计学中，特征选择（英语：feature selection）也被称为变量选择、属性选择 或变量子集选择 。它是指：为了构建模型而选择相关特征（即属性、指标）子集的过程。使用特征选择技术有三个原因：\n",
    "\n",
    "    简化模型，使之更易于被研究人员或用户理解，\n",
    "    缩短训练时间，\n",
    "    改善通用性、降低过拟合（即降低方差）。\n",
    "\n",
    "要使用特征选择技术的关键假设是：训练数据包含许多冗余 或无关 的特征，因而移除这些特征并不会导致丢失信息。 冗余 或无关 特征是两个不同的概念。如果一个特征本身有用，但如果这个特征与另一个有用特征强相关，且那个特征也出现在数据中，那么这个特征可能就变得多余。\n",
    "特征选择技术与特征提取有所不同。特征提取是从原有特征的功能中创造新的特征，而特征选择则只返回原有特征中的子集。 特征选择技术的常常用于许多特征但样本（即数据点）相对较少的领域。特征选择应用的典型用例包括：解析书面文本和微阵列数据，这些场景下特征成千上万，但样本只有几十到几百个。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.model_selection import cross_val_score\n",
    "from sklearn.ensemble import RandomForestClassifier\n",
    "\n",
    "def feature_selection(train, train_sel, target):\n",
    "    clf = RandomForestClassifier(n_estimators=100, max_depth=2, random_state=0, n_jobs=-1)\n",
    "    \n",
    "    scores = cross_val_score(clf, train, target, cv=5)\n",
    "    scores_sel = cross_val_score(clf, train_sel, target, cv=5)\n",
    "    \n",
    "    print(\"No Select Accuracy: %0.2f (+/- %0.2f)\" % (scores.mean(), scores.std() * 2))     \n",
    "    print(\"Features Select Accuracy: %0.2f (+/- %0.2f)\" % (scores.mean(), scores.std() * 2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 删除方差较小的要素（方法一）\n",
    "VarianceThreshold是一种简单的基线特征选择方法。它会删除方差不符合某个阈值的所有要素。默认情况下，它会删除所有零方差要素，即在所有样本中具有相同值的要素。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.feature_selection import VarianceThreshold\n",
    "\n",
    "sel = VarianceThreshold(threshold=(.8 * (1 - .8)))\n",
    "sel = sel.fit(train)\n",
    "train_sel = sel.transform(train)\n",
    "test_sel = sel.transform(test)\n",
    "print('训练数据未特征筛选维度', train.shape)\n",
    "print('训练数据特征筛选维度后', train_sel.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "### 特征选择前后区别\n",
    "feature_selection(train, train_sel, target)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 单变量特征选择（方法二）\n",
    "通过基于单变量统计检验选择最佳特征。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.feature_selection import SelectKBest\n",
    "# from sklearn.feature_selection import chi2\n",
    "from sklearn.feature_selection import mutual_info_classif\n",
    "\n",
    "sel = SelectKBest(mutual_info_classif, k=2)\n",
    "sel = sel.fit(train, target)\n",
    "train_sel = sel.transform(train)\n",
    "test_sel = sel.transform(test)\n",
    "print('训练数据未特征筛选维度', train.shape)\n",
    "print('训练数据特征筛选维度后', train_sel.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "### 特征选择前后区别\n",
    "feature_selection(train, train_sel, target)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 递归功能消除（方法三）\n",
    "选定模型拟合，进行递归拟合，每次把评分低得特征去除，重复上诉循环。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.feature_selection import RFECV\n",
    "from sklearn.ensemble import RandomForestClassifier\n",
    "\n",
    "clf = RandomForestClassifier(n_estimators=10, max_depth=2, random_state=0, n_jobs=-1)\n",
    "selector = RFECV(clf, step=1, cv=2)\n",
    "selector = selector.fit(train, target)\n",
    "print(selector.support_)\n",
    "print(selector.ranking_)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 使用模型选择特征（方法四）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 使用LR拟合的参数进行变量选择（L2范数进行特征选择）\n",
    "LR模型采用拟合参数形式进行变量选择，筛选对回归目标影响大的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.feature_selection import SelectFromModel\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "from sklearn.preprocessing import Normalizer\n",
    "\n",
    "normalizer = Normalizer()\n",
    "normalizer = normalizer.fit(train)  \n",
    "\n",
    "train_norm = normalizer.transform(train)                            \n",
    "test_norm = normalizer.transform(test)\n",
    "\n",
    "LR = LogisticRegression(penalty='l2',C=5)\n",
    "LR = LR.fit(train_norm, target)\n",
    "model = SelectFromModel(LR, prefit=True)\n",
    "train_sel = model.transform(train)\n",
    "test_sel = model.transform(test)\n",
    "print('训练数据未特征筛选维度', train.shape)\n",
    "print('训练数据特征筛选维度后', train_sel.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "### 特征选择前后区别\n",
    "feature_selection(train, train_sel, target)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 使用LR拟合的参数进行变量选择（L1范数进行特征选择）\n",
    "LR模型采用拟合参数形式进行变量选择，筛选对回归目标影响大的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.feature_selection import SelectFromModel\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "from sklearn.preprocessing import Normalizer\n",
    "\n",
    "normalizer = Normalizer()\n",
    "normalizer = normalizer.fit(train)  \n",
    "\n",
    "train_norm = normalizer.transform(train)                            \n",
    "test_norm = normalizer.transform(test)\n",
    "\n",
    "LR = LogisticRegression(penalty='l1',C=5)\n",
    "LR = LR.fit(train_norm, target)\n",
    "model = SelectFromModel(LR, prefit=True)\n",
    "train_sel = model.transform(train)\n",
    "test_sel = model.transform(test)\n",
    "print('训练数据未特征筛选维度', train.shape)\n",
    "print('训练数据特征筛选维度后', train_sel.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "### 特征选择前后区别\n",
    "feature_selection(train, train_sel, target)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 基于树模型特征选择\n",
    "树模型基于分裂评价标准所计算的总的评分作为依据进行相关排序，然后进行特征筛选"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.ensemble import ExtraTreesClassifier\n",
    "from sklearn.feature_selection import SelectFromModel\n",
    "\n",
    "clf = ExtraTreesClassifier(n_estimators=50)\n",
    "clf = clf.fit(train, target)\n",
    "\n",
    "model = SelectFromModel(clf, prefit=True)\n",
    "train_sel = model.transform(train)\n",
    "test_sel = model.transform(test)\n",
    "print('训练数据未特征筛选维度', train.shape)\n",
    "print('训练数据特征筛选维度后', train_sel.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#### 树特征重要性\n",
    "clf.feature_importances_[:10]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "### 特征选择前后区别\n",
    "feature_selection(train, train_sel, target)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Lgb特征重要性"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import lightgbm\n",
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "X_train, X_test, y_train, y_test = train_test_split(train, target, test_size=0.4, random_state=0)\n",
    "\n",
    "clf = lightgbm\n",
    "\n",
    "train_matrix = clf.Dataset(X_train, label=y_train)\n",
    "test_matrix = clf.Dataset(X_test, label=y_test)\n",
    "params = {\n",
    "          'boosting_type': 'gbdt',\n",
    "          #'boosting_type': 'dart',\n",
    "          'objective': 'multiclass',\n",
    "          'metric': 'multi_logloss',\n",
    "          'min_child_weight': 1.5,\n",
    "          'num_leaves': 2**5,\n",
    "          'lambda_l2': 10,\n",
    "          'subsample': 0.7,\n",
    "          'colsample_bytree': 0.7,\n",
    "          'colsample_bylevel': 0.7,\n",
    "          'learning_rate': 0.03,\n",
    "          'tree_method': 'exact',\n",
    "          'seed': 2017,\n",
    "          \"num_class\": 2,\n",
    "          'silent': True,\n",
    "          }\n",
    "num_round = 10000\n",
    "early_stopping_rounds = 100\n",
    "model = clf.train(params, \n",
    "                  train_matrix,\n",
    "                  num_round,\n",
    "                  valid_sets=test_matrix,\n",
    "                  early_stopping_rounds=early_stopping_rounds)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def lgb_transform(train, test, model, topK):\n",
    "    train_df = pd.DataFrame(train)\n",
    "    train_df.columns = range(train.shape[1])\n",
    "    \n",
    "    test_df = pd.DataFrame(test)\n",
    "    test_df.columns = range(test.shape[1])\n",
    "    \n",
    "    features_import = pd.DataFrame()\n",
    "    features_import['importance'] = model.feature_importance()\n",
    "    features_import['col'] = range(train.shape[1])\n",
    "    \n",
    "    features_import = features_import.sort_values(['importance'],ascending=0).head(topK)\n",
    "    sel_col = list(features_import.col)\n",
    "    \n",
    "    train_sel = train_df[sel_col]\n",
    "    test_sel = test_df[sel_col]\n",
    "    return train_sel, test_sel\n",
    "\n",
    "train_sel, test_sel = lgb_transform(train, test, model, 20)\n",
    "print('训练数据未特征筛选维度', train.shape)\n",
    "print('训练数据特征筛选维度后', train_sel.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#  lgb特征重要性\n",
    "model.feature_importance()[:10]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "feature_selection(train, train_sel, target)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:all] *",
   "language": "python",
   "name": "conda-env-all-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.9"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
